├── .gitignore ├── README.md └── src └── net └── buddat └── wgenerator ├── HeightMap.java ├── TileMap.java ├── WGenerator.java ├── ui └── MapPanel.java └── util ├── Constants.java └── SimplexNoise.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MapGenerator 2 | Basic map generation designed for Wurm maps 3 | 4 | # Controls 5 | Space: Generate a new map (includes base layer and an amount of detail levels) 6 | 7 | Enter: Generate a new base layer for a new map 8 | 9 | Control: Step through adding detail to the map 10 | 11 | C: Delete any land below a certain point (Do not use for realistic maps) 12 | 13 | E: Erode land (Warning: Takes a long time, especially for larger maps) 14 | 15 | G: Seed grass 16 | 17 | S: Show render of the map 18 | -------------------------------------------------------------------------------- /src/net/buddat/wgenerator/HeightMap.java: -------------------------------------------------------------------------------- 1 | package net.buddat.wgenerator; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | 6 | import net.buddat.wgenerator.util.SimplexNoise; 7 | 8 | /** 9 | * @author Budda 10 | * 11 | * Generates a heightmap with bounds set in the constructor. 12 | * All height values for each point will be between 0.0 and 1.0 13 | */ 14 | public class HeightMap { 15 | 16 | private static final Logger logger = Logger.getLogger(HeightMap.class.getName()); 17 | 18 | private double[][] heightArray; 19 | 20 | private long noiseSeed; 21 | 22 | private int mapSize; 23 | 24 | private double resolution; 25 | 26 | private int iterations; 27 | 28 | private boolean moreLand; 29 | 30 | private int minimumEdge; 31 | 32 | private int maxHeight; 33 | 34 | private int borderCutoff; 35 | 36 | private float borderNormalize; 37 | 38 | private double singleDirt; 39 | 40 | public HeightMap(long seed, int mapSize, double resolution, int iterations, int minimumEdge, double borderWeight, int maxHeight, boolean moreLand) { 41 | this.noiseSeed = seed; 42 | this.mapSize = mapSize; 43 | this.resolution = resolution; 44 | this.iterations = iterations; 45 | this.minimumEdge = minimumEdge; 46 | this.maxHeight = maxHeight; 47 | this.moreLand = moreLand; 48 | 49 | this.heightArray = new double[mapSize][mapSize]; 50 | this.borderCutoff = (int) (mapSize / borderWeight); 51 | this.borderNormalize = (float) (1.0f / borderCutoff); 52 | 53 | this.singleDirt = 1.0 / maxHeight; 54 | 55 | logger.setLevel(Level.INFO); 56 | } 57 | 58 | /** 59 | * Generates a full heightmap with the current instance's set values. 60 | * Clamps the heightmap heights for the last iteration only. 61 | */ 62 | public void generateHeights() { 63 | logger.log(Level.INFO, "HeightMap seed set to: " + noiseSeed); 64 | SimplexNoise.genGrad(noiseSeed); 65 | 66 | long startTime = System.currentTimeMillis(); 67 | for (int i = 0; i < iterations; i++) { 68 | logger.log(Level.FINE, "HeightMap Generation (" + mapSize + ") - Iteration(" + (i + 1) + "/" + iterations + ")"); 69 | 70 | double iRes = resolution / Math.pow(2, i - 1); 71 | double str = Math.pow(2, i - 1) * 2.0; 72 | 73 | for (int x = 0; x < mapSize; x++) 74 | for (int y = 0; y < mapSize; y++) 75 | setHeight(x, y, getHeight(x, y) + SimplexNoise.noise(x / iRes, y / iRes) / str, (i == iterations - 1)); 76 | } 77 | 78 | logger.log(Level.INFO, "HeightMap Generation (" + mapSize + ") completed in " + (System.currentTimeMillis() - startTime) + "ms."); 79 | 80 | normalizeHeights(); 81 | } 82 | 83 | public void normalizeHeights() { 84 | long startTime = System.currentTimeMillis(); 85 | 86 | double maxHeight = 0.0f; 87 | for (int i = 0; i < mapSize; i++) { 88 | for (int j = 0; j < mapSize; j++) { 89 | if (getHeight(i, j) > maxHeight) 90 | maxHeight = getHeight(i, j); 91 | } 92 | } 93 | 94 | double normalize = 1.0f / maxHeight; 95 | for (int i = 0; i < mapSize; i++) 96 | for (int j = 0; j < mapSize; j++) 97 | setHeight(i, j, getHeight(i, j) * normalize, false); 98 | 99 | double normalizeLow = 1.0 / 0.5; 100 | double normalizeHigh = 2.0f / 0.5; 101 | for (int i = 0; i < mapSize; i++) 102 | for (int j = 0; j < mapSize; j++) { 103 | if (getHeight(i, j) < 0.5) { 104 | setHeight(i, j, (getHeight(i, j) * normalizeLow) / 3.0, false); 105 | } else { 106 | double newHeight = 1.0f + (getHeight(i, j) - 0.5) * normalizeHigh; 107 | setHeight(i, j, newHeight / 3.0, false); 108 | } 109 | } 110 | 111 | logger.log(Level.INFO, "HeightMap Normalization (" + mapSize + ") completed in " + (System.currentTimeMillis() - startTime) + "ms."); 112 | } 113 | 114 | public void erode(int iterations, int minSlope, int sedimentMax) { 115 | long startTime = System.currentTimeMillis(); 116 | 117 | for (int iter = 0; iter < iterations; iter++) { 118 | for (int i = 0; i < mapSize; i++) { 119 | for (int j = 0; j < mapSize; j++) { 120 | double neighbours[] = new double[4]; 121 | double currentTile = heightArray[i][j]; 122 | 123 | neighbours[0] = heightArray[clamp(i - 1, 0, mapSize - 1)][j]; 124 | neighbours[1] = heightArray[i][clamp(j - 1, 0, mapSize - 1)]; 125 | neighbours[2] = heightArray[clamp(i + 1, 0, mapSize - 1)][j]; 126 | neighbours[3] = heightArray[i][clamp(j + 1, 0, mapSize - 1)]; 127 | 128 | int lowest = 0; 129 | double maxDiff = 0.0; 130 | for (int k = 0; k < 3; k++) { 131 | double diff = currentTile - neighbours[k]; 132 | if (diff > maxDiff) { 133 | maxDiff = diff; 134 | lowest = k; 135 | } 136 | } 137 | 138 | double sediment = 0.0; 139 | if (maxDiff > minSlope * singleDirt) { 140 | sediment = (sedimentMax * singleDirt) * maxDiff; 141 | currentTile -= sediment; 142 | neighbours[lowest] += sediment; 143 | } 144 | 145 | setHeight(i, j, currentTile, false); 146 | setHeight(clamp(i - 1, 0, mapSize - 1), j, neighbours[0], false); 147 | setHeight(i, clamp(j - 1, 0, mapSize - 1), neighbours[1], false); 148 | setHeight(clamp(i + 1, 0, mapSize - 1), j, neighbours[2], false); 149 | setHeight(i, clamp(j + 1, 0, mapSize - 1), neighbours[3], false); 150 | } 151 | } 152 | } 153 | 154 | logger.log(Level.INFO, "HeightMap Erosion (" + iterations + ") completed in " + (System.currentTimeMillis() - startTime) + "ms."); 155 | } 156 | 157 | public double[][] getHeightArray() { 158 | return heightArray; 159 | } 160 | 161 | public double getHeight(int x, int y) { 162 | return heightArray[x][y]; 163 | } 164 | 165 | /** 166 | * @param x Location x 167 | * @param y Location y 168 | * @param newHeight Height to set the location to 169 | * @param clamp Whether to clamp the location's height depending on x/y and the border cutoff (Constants.BORDER_WEIGHT) 170 | * @return The height that was set after constraints and clamping 171 | */ 172 | public double setHeight(int x, int y, double newHeight, boolean clamp) { 173 | if (newHeight < (moreLand ? -1d : 0)) 174 | newHeight = (moreLand ? -1d : 0); 175 | if (newHeight > 1d) 176 | newHeight = 1d; 177 | 178 | heightArray[x][y] = newHeight; 179 | 180 | if (clamp) { 181 | if (moreLand) 182 | heightArray[x][y] = (heightArray[x][y] + 1) * 0.5d; 183 | 184 | if (x <= borderCutoff + minimumEdge || y <= borderCutoff + minimumEdge) { 185 | if (x < y) 186 | heightArray[x][y] *= Math.max(0, ((Math.min(x, mapSize - y) - minimumEdge)) * borderNormalize); 187 | else 188 | heightArray[x][y] *= Math.max(0, ((Math.min(y, mapSize - x) - minimumEdge)) * borderNormalize); 189 | } else if (mapSize - x <= borderCutoff + minimumEdge || mapSize - y <= borderCutoff + minimumEdge) { 190 | heightArray[x][y] *= Math.max(0, ((Math.min(mapSize - x, mapSize - y) - minimumEdge)) * borderNormalize); 191 | } 192 | } 193 | 194 | return heightArray[x][y]; 195 | } 196 | 197 | public long getSeed() { 198 | return noiseSeed; 199 | } 200 | 201 | public void setSeed(long newSeed) { 202 | this.noiseSeed = newSeed; 203 | } 204 | 205 | public int getMaxHeight() { 206 | return maxHeight; 207 | } 208 | 209 | public void setMaxHeight(int newMaxHeight) { 210 | this.maxHeight = newMaxHeight; 211 | } 212 | 213 | public int getMapSize() { 214 | return mapSize; 215 | } 216 | 217 | /** 218 | * @param newSize Size to set the map to 219 | * 220 | * We don't want to set the map size after construction. 221 | * To generate a new map at a different size, create a new instance. 222 | */ 223 | protected void setMapSize(int newSize) { 224 | this.mapSize = newSize; 225 | } 226 | 227 | public double getResolution() { 228 | return resolution; 229 | } 230 | 231 | public void setResolution(double newResolution) { 232 | this.resolution = newResolution; 233 | } 234 | 235 | public int getIterations() { 236 | return iterations; 237 | } 238 | 239 | public void setIterations(int newIterations) { 240 | this.iterations = newIterations; 241 | } 242 | 243 | public double getSingleDirt() { 244 | return singleDirt; 245 | } 246 | 247 | public static int clamp(int val, int min, int max) { 248 | return Math.max(min, Math.min(max, val)); 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /src/net/buddat/wgenerator/TileMap.java: -------------------------------------------------------------------------------- 1 | package net.buddat.wgenerator; 2 | 3 | import java.awt.Point; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.Random; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | import com.wurmonline.mesh.Tiles.Tile; 11 | 12 | public class TileMap { 13 | 14 | private static final Logger logger = Logger.getLogger(TileMap.class.getName()); 15 | 16 | private Random biomeRandom; 17 | 18 | private HeightMap heightMap; 19 | 20 | private Tile[][] typeMap; 21 | 22 | private Tile[][] oreTypeMap; 23 | 24 | private short[][] oreResourceMap; 25 | 26 | private short[][] dirtMap; 27 | 28 | private double singleDirt; 29 | 30 | private int biomeSeed; 31 | 32 | private double waterHeight; 33 | 34 | private boolean hasOres; 35 | 36 | private HashMap lastBiomeChanges; 37 | 38 | public TileMap(HeightMap heightMap) { 39 | this.heightMap = heightMap; 40 | this.singleDirt = heightMap.getSingleDirt(); 41 | 42 | this.typeMap = new Tile[heightMap.getMapSize()][heightMap.getMapSize()]; 43 | this.oreTypeMap = new Tile[heightMap.getMapSize()][heightMap.getMapSize()]; 44 | this.oreResourceMap = new short[heightMap.getMapSize()][heightMap.getMapSize()]; 45 | this.dirtMap = new short[heightMap.getMapSize()][heightMap.getMapSize()]; 46 | 47 | this.hasOres = false; 48 | 49 | this.lastBiomeChanges = new HashMap(); 50 | } 51 | 52 | public void dropDirt(int dirtCount, int maxSlope, int maxDiagSlope, int maxDirtHeight) { 53 | double maxSlopeHeight = maxSlope * singleDirt; 54 | double maxDiagSlopeHeight = maxDiagSlope * singleDirt; 55 | double maxHeight = maxDirtHeight * singleDirt; 56 | double taperHeight = maxHeight - ((dirtCount * 2) * singleDirt); 57 | 58 | long startTime = System.currentTimeMillis(); 59 | for (int i = 0; i < dirtCount; i++) { 60 | for (int x = 0; x < heightMap.getMapSize(); x++) { 61 | for (int y = 0; y < heightMap.getMapSize(); y++) { 62 | if (heightMap.getHeight(x, y) > maxHeight) 63 | continue; 64 | 65 | if (heightMap.getHeight(x, y) > taperHeight) 66 | if ((maxHeight - heightMap.getHeight(x, y)) * heightMap.getMaxHeight() < i) 67 | continue; 68 | 69 | Point dropTile = findDropTile(x, y, maxSlopeHeight, maxDiagSlopeHeight); 70 | 71 | addDirt((int) dropTile.getX(), (int) dropTile.getY(), 1); 72 | } 73 | } 74 | } 75 | 76 | logger.log(Level.INFO, "Dirt Dropping (" + dirtCount + ") completed in " + (System.currentTimeMillis() - startTime) + "ms."); 77 | } 78 | 79 | public void generateOres(double[] rates) { 80 | long startTime = System.currentTimeMillis(); 81 | 82 | for (int x = 0; x < heightMap.getMapSize(); x++) { 83 | for (int y = 0; y < heightMap.getMapSize(); y++) { 84 | double rand = biomeRandom.nextDouble() * 100; 85 | double total; 86 | 87 | if (rand < (total = rates[0])) 88 | setOreType(x, y, Tile.TILE_CAVE_WALL, biomeRandom.nextInt(20) + 40); 89 | else if (rand < (total += rates[1])) 90 | setOreType(x, y, Tile.TILE_CAVE_WALL_ORE_IRON, biomeRandom.nextInt(15000) + 90); 91 | else if (rand < (total += rates[2])) 92 | setOreType(x, y, Tile.TILE_CAVE_WALL_ORE_GOLD, biomeRandom.nextInt(15000) + 90); 93 | else if (rand < (total += rates[3])) 94 | setOreType(x, y, Tile.TILE_CAVE_WALL_ORE_SILVER, biomeRandom.nextInt(15000) + 90); 95 | else if (rand < (total += rates[4])) 96 | setOreType(x, y, Tile.TILE_CAVE_WALL_ORE_ZINC, biomeRandom.nextInt(15000) + 90); 97 | else if (rand < (total += rates[5])) 98 | setOreType(x, y, Tile.TILE_CAVE_WALL_ORE_COPPER, biomeRandom.nextInt(15000) + 90); 99 | else if (rand < (total += rates[6])) 100 | setOreType(x, y, Tile.TILE_CAVE_WALL_ORE_LEAD, biomeRandom.nextInt(15000) + 90); 101 | else if (rand < (total += rates[7])) 102 | setOreType(x, y, Tile.TILE_CAVE_WALL_ORE_TIN, biomeRandom.nextInt(15000) + 90); 103 | else if (rand < (total += rates[8])) 104 | setOreType(x, y, Tile.TILE_CAVE_WALL_ORE_ADAMANTINE, biomeRandom.nextInt(15000) + 90); 105 | else if (rand < (total += rates[9])) 106 | setOreType(x, y, Tile.TILE_CAVE_WALL_ORE_GLIMMERSTEEL, biomeRandom.nextInt(15000) + 90); 107 | else if (rand < (total += rates[10])) 108 | setOreType(x, y, Tile.TILE_CAVE_WALL_MARBLE, biomeRandom.nextInt(15000) + 90); 109 | else if (rand < (total += rates[11])) 110 | setOreType(x, y, Tile.TILE_CAVE_WALL_SLATE, biomeRandom.nextInt(15000) + 90); 111 | else 112 | setOreType(x, y, Tile.TILE_CAVE_WALL, biomeRandom.nextInt(20) + 40); 113 | } 114 | } 115 | 116 | hasOres = true; 117 | 118 | logger.log(Level.INFO, "Ore Generation completed in " + (System.currentTimeMillis() - startTime) + "ms."); 119 | } 120 | 121 | public void undoLastBiome() { 122 | for (Point p : lastBiomeChanges.keySet()) 123 | setType(p, lastBiomeChanges.get(p)); 124 | } 125 | 126 | public void plantBiome(int seedCount, int growthIterations, double[] growthRate, int maxBiomeSlope, int minHeight, int maxHeight, Tile type) { 127 | long startTime = System.currentTimeMillis(); 128 | 129 | ArrayList grassList = new ArrayList(); 130 | ArrayList nextList = new ArrayList(); 131 | 132 | lastBiomeChanges.clear(); 133 | 134 | for (int i = 0; i < seedCount; i++) 135 | grassList.add(new Point(biomeRandom.nextInt(heightMap.getMapSize()), biomeRandom.nextInt(heightMap.getMapSize()))); 136 | 137 | for (int i = 0; i < growthIterations; i++) { 138 | nextList = growBiome(grassList, type, growthRate, maxBiomeSlope, minHeight, maxHeight); 139 | grassList = growBiome(nextList, type, growthRate, maxBiomeSlope, minHeight, maxHeight); 140 | } 141 | 142 | logger.log(Level.INFO, "Biome Seeding (" + type.tilename + ") completed in " + (System.currentTimeMillis() - startTime) + "ms."); 143 | } 144 | 145 | public ArrayList growBiome(ArrayList fromList, Tile type, double[] growthRate, int maxBiomeSlope, int minHeight, int maxHeight) { 146 | ArrayList nextList = new ArrayList(); 147 | 148 | int dirMod = (type.isTree() ? biomeRandom.nextInt(6) + 2 : (type.isBush() ? biomeRandom.nextInt(3) + 2 : 1)); 149 | 150 | for (Point p : fromList) { 151 | if (biomeRandom.nextDouble() < growthRate[0]) { //North 152 | Point nT = new Point((int) p.getX(), HeightMap.clamp((int) (p.getY() - dirMod), 0, heightMap.getMapSize() - 1)); 153 | if (setBiome(p, nT, maxBiomeSlope * dirMod, type, minHeight, maxHeight)) 154 | nextList.add(nT); 155 | } 156 | 157 | if (biomeRandom.nextDouble() < growthRate[1]) { //South 158 | Point nT = new Point((int) p.getX(), HeightMap.clamp((int) (p.getY() + dirMod), 0, heightMap.getMapSize() - 1)); 159 | if (setBiome(p, nT, maxBiomeSlope * dirMod, type, minHeight, maxHeight)) 160 | nextList.add(nT); 161 | } 162 | 163 | if (biomeRandom.nextDouble() < growthRate[2]) { //East 164 | Point nT = new Point(HeightMap.clamp((int) (p.getX() + dirMod), 0, heightMap.getMapSize() - 1), (int) p.getY()); 165 | if (setBiome(p, nT, maxBiomeSlope * dirMod, type, minHeight, maxHeight)) 166 | nextList.add(nT); 167 | } 168 | 169 | if (biomeRandom.nextDouble() < growthRate[3]) { //West 170 | Point nT = new Point(HeightMap.clamp((int) (p.getX() - dirMod), 0, heightMap.getMapSize() - 1), (int) p.getY()); 171 | if (setBiome(p, nT, maxBiomeSlope * dirMod, type, minHeight, maxHeight)) 172 | nextList.add(nT); 173 | } 174 | } 175 | 176 | return nextList; 177 | } 178 | 179 | private boolean setBiome(Point from, Point to, int maxBiomeSlope, Tile type, int minHeight, int maxHeight) { 180 | if (getType((int) to.getX(), (int) to.getY()) == Tile.TILE_ROCK) 181 | return false; 182 | 183 | if (from != null) 184 | if (getDifference(from, to) > (singleDirt * maxBiomeSlope)) 185 | return false; 186 | 187 | if (getTileHeight((int) to.getX(), (int) to.getY()) < (singleDirt * minHeight)) 188 | return false; 189 | 190 | if (getTileHeight((int) to.getX(), (int) to.getY()) > (singleDirt * maxHeight)) 191 | return false; 192 | 193 | Tile originalTileType = getType((int) to.getX(), (int) to.getY()); 194 | if (originalTileType != type) { 195 | if((!type.isTree() && !type.isBush()) || originalTileType == Tile.TILE_GRASS) { 196 | lastBiomeChanges.put(to, getType(to)); 197 | 198 | setType(to, type); 199 | return true; 200 | } 201 | } 202 | 203 | return false; 204 | } 205 | 206 | public Tile getType(int x, int y) { 207 | if (typeMap[x][y] == null) 208 | return Tile.TILE_ROCK; 209 | 210 | return typeMap[x][y]; 211 | } 212 | 213 | public Tile getType(Point p) { 214 | return getType((int) p.getX(), (int) p.getY()); 215 | } 216 | 217 | public void setType(int x, int y, Tile newType) { 218 | typeMap[x][y] = newType; 219 | } 220 | 221 | public void setType(Point p, Tile newType) { 222 | setType((int) p.getX(), (int) p.getY(), newType); 223 | } 224 | 225 | public Tile getOreType(int x, int y) { 226 | if (oreTypeMap[x][y] == null) 227 | return Tile.TILE_CAVE_WALL; 228 | 229 | return oreTypeMap[x][y]; 230 | } 231 | 232 | public Tile getOreType(Point p) { 233 | return getOreType((int) p.getX(), (int) p.getY()); 234 | } 235 | 236 | public void setOreCount(int x, int y, int resourceCount) { 237 | oreResourceMap[x][y] = (short) resourceCount; 238 | } 239 | 240 | public short getOreCount(int x, int y) { 241 | return oreResourceMap[x][y]; 242 | } 243 | 244 | public void setOreType(int x, int y, Tile newType, int resourceCount) { 245 | if (!newType.isCave()) 246 | newType = Tile.TILE_CAVE_WALL; 247 | 248 | oreTypeMap[x][y] = newType; 249 | setOreCount(x, y, resourceCount); 250 | } 251 | 252 | public void setOreType(Point p, Tile newType, short resourceCount) { 253 | setOreType((int) p.getX(), (int) p.getY(), newType, resourceCount); 254 | } 255 | 256 | public boolean hasOres() { 257 | return hasOres; 258 | } 259 | 260 | public short getDirt(int x, int y) { 261 | return dirtMap[x][y]; 262 | } 263 | 264 | public void setDirt(int x, int y, short newDirt) { 265 | if (newDirt < 0) 266 | newDirt = 0; 267 | 268 | if (newDirt > 0) { 269 | if (getTileHeight(x, y) >= waterHeight) 270 | setType(x, y, Tile.TILE_GRASS); 271 | else 272 | setType(x, y, Tile.TILE_DIRT); 273 | } 274 | 275 | dirtMap[x][y] = newDirt; 276 | } 277 | 278 | public void addDirt(int x, int y, int count) { 279 | setDirt(x, y, (short) (getDirt(x, y) + count)); 280 | } 281 | 282 | public double getDirtHeight(int x, int y) { 283 | return getDirt(x, y) * singleDirt; 284 | } 285 | 286 | public double getTileHeight(int x, int y) { 287 | return heightMap.getHeight(x, y) + getDirtHeight(x, y); 288 | } 289 | 290 | public short getSurfaceHeight(int x, int y) { 291 | return (short) ((getTileHeight(x, y) - getWaterHeight()) * heightMap.getMaxHeight()); 292 | } 293 | 294 | public short getRockHeight(int x, int y) { 295 | return (short) ((heightMap.getHeight(x, y) - getWaterHeight()) * heightMap.getMaxHeight()); 296 | } 297 | 298 | public double getDifference(int x1, int y1, int x2, int y2) { 299 | return Math.abs(getTileHeight(x1, y1) - getTileHeight(x2, y2)); 300 | } 301 | 302 | public double getDifference(Point p, Point p2) { 303 | return getDifference((int) p.getX(), (int) p.getY(), (int) p2.getX(), (int) p2.getY()); 304 | } 305 | 306 | public HeightMap getHeightMap() { 307 | return heightMap; 308 | } 309 | 310 | public void setHeightMap(HeightMap newMap) { 311 | this.heightMap = newMap; 312 | } 313 | 314 | public int getBiomeSeed() { 315 | return biomeSeed; 316 | } 317 | 318 | public void setBiomeSeed(int newSeed) { 319 | this.biomeSeed = newSeed; 320 | 321 | biomeRandom = new Random(newSeed); 322 | } 323 | 324 | public double getWaterHeight() { 325 | return waterHeight; 326 | } 327 | 328 | public void setWaterHeight(int newHeight) { 329 | this.waterHeight = newHeight * singleDirt; 330 | } 331 | 332 | private Point findDropTile(int x, int y, double maxSlope, double maxDiagSlope) { 333 | ArrayList slopes = new ArrayList(); 334 | double currentHeight = getTileHeight(x, y); 335 | 336 | for (int i = x + 1; i >= x - 1; i--) { 337 | for (int j = y + 1; j >= y - 1; j--) { 338 | if (i < 0 || j < 0 || i >= heightMap.getMapSize() || j >= heightMap.getMapSize()) 339 | continue; 340 | 341 | double thisHeight = getTileHeight(i, j); 342 | if ((i == 0 && j != 0) || (i != 0 && j == 0)) 343 | if (thisHeight <= currentHeight - maxSlope) 344 | slopes.add(new Point(i, j)); 345 | 346 | if (i != 0 && y != 0) 347 | if (thisHeight <= currentHeight - maxDiagSlope) 348 | slopes.add(new Point(i, j)); 349 | } 350 | } 351 | 352 | if (slopes.size() > 0) { 353 | int r = biomeRandom.nextInt(slopes.size()); 354 | return findDropTile((int) slopes.get(r).getX(), (int) slopes.get(r).getY(), maxSlope, maxDiagSlope); 355 | } else { 356 | return new Point(x, y); 357 | } 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /src/net/buddat/wgenerator/WGenerator.java: -------------------------------------------------------------------------------- 1 | package net.buddat.wgenerator; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Color; 5 | import java.awt.Dimension; 6 | import java.awt.FlowLayout; 7 | import java.awt.Graphics; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | import java.awt.event.FocusEvent; 11 | import java.awt.event.FocusListener; 12 | import java.io.BufferedReader; 13 | import java.io.BufferedWriter; 14 | import java.io.File; 15 | import java.io.FileReader; 16 | import java.io.FileWriter; 17 | import java.io.IOException; 18 | import java.util.ArrayList; 19 | import java.util.Random; 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | 23 | import javax.imageio.ImageIO; 24 | import javax.swing.BorderFactory; 25 | import javax.swing.BoxLayout; 26 | import javax.swing.JButton; 27 | import javax.swing.JCheckBox; 28 | import javax.swing.JComboBox; 29 | import javax.swing.JFileChooser; 30 | import javax.swing.JFrame; 31 | import javax.swing.JLabel; 32 | import javax.swing.JOptionPane; 33 | import javax.swing.JPanel; 34 | import javax.swing.JTextField; 35 | import javax.swing.border.Border; 36 | import javax.swing.border.EmptyBorder; 37 | import javax.swing.filechooser.FileFilter; 38 | import javax.swing.filechooser.FileView; 39 | 40 | import com.wurmonline.mesh.FoliageAge; 41 | import com.wurmonline.mesh.GrassData.GrowthTreeStage; 42 | import com.wurmonline.mesh.Tiles.Tile; 43 | import com.wurmonline.wurmapi.api.MapData; 44 | import com.wurmonline.wurmapi.api.WurmAPI; 45 | 46 | import net.buddat.wgenerator.ui.MapPanel; 47 | import net.buddat.wgenerator.util.Constants; 48 | 49 | public class WGenerator extends JFrame implements ActionListener, FocusListener { 50 | 51 | private static final long serialVersionUID = 3099528642510249703L; 52 | 53 | private static final Logger logger = Logger.getLogger(WGenerator.class.getName()); 54 | 55 | private WurmAPI api; 56 | 57 | private HeightMap heightMap; 58 | 59 | private TileMap tileMap; 60 | 61 | private MapPanel pnlMap; 62 | 63 | private JPanel pnlControls, pnlHeightMapControls, pnlHeightMapOptions, pnlHeightMapOptions2, pnlHeightMapOptions3, 64 | pnlHeightMapOptionsMiddle, pnlHeightMapOptionsMiddleTop, pnlHeightMapOptionsMiddleBottom; 65 | private JPanel pnlErodeControls, pnlErodeOptions, pnlErodeOptions2, pnlErodeButton; 66 | private JPanel pnlDirtControls, pnlDirtOptions, pnlDirtOptions2, pnlDirtOptions3, pnlDirtOptionsMiddle, pnlDirtButton; 67 | private JPanel pnlBiomeControls, pnlBiomeOptions, pnlBiomeOptions2, pnlBiomeOptions3, pnlBiomeOptionsMiddle, pnlBiomeButton; 68 | private JPanel pnlOreControls, pnlOreOptions, pnlOreOptions2, pnlOreOptions3, pnlOreOptions4, pnlOreOptionsMiddle, pnlOreButton; 69 | private JPanel pnlSaveControls, pnlSaveOptions; 70 | 71 | private JLabel lblMapSize, lblSeed, lblRes, lblIterations, lblMinEdge, lblBorderWeight, lblMaxHeight; 72 | private JLabel lblErodeIterations, lblErodeMinSlope, lblErodeMaxSediment; 73 | private JLabel lblBiomeSeed, lblDirtAmnt, lblDirtSlope, lblDirtDiagSlope, lblMaxDirtHeight, lblWaterHeight; 74 | private JLabel lblBiomeSeedCount, lblBiomeSize, lblBiomeMaxSlope, lblBiomeRate, lblBiomeMinHeight, lblBiomeMaxHeight; 75 | private JLabel lblRock, lblIron, lblGold, lblSilver, lblZinc, lblCopper, lblLead, lblTin, lblAddy, lblGlimmer, lblMarble, lblSlate; 76 | 77 | private JTextField txtSeed, txtRes, txtIterations, txtMinEdge, txtBorderWeight, txtMaxHeight; 78 | private JTextField txtErodeIterations, txtErodeMinSlope, txtErodeMaxSediment; 79 | private JTextField txtBiomeSeed, txtDirtAmnt, txtDirtSlope, txtDirtDiagSlope, txtMaxDirtHeight, txtWaterHeight; 80 | private JTextField txtBiomeSeedCount, txtBiomeSize, txtBiomeMaxSlope, txtBiomeRateN, txtBiomeRateS, txtBiomeRateE, txtBiomeRateW, 81 | txtBiomeMinHeight, txtBiomeMaxHeight; 82 | private JTextField txtRock, txtIron, txtGold, txtSilver, txtZinc, txtCopper, txtLead, txtTin, txtAddy, txtGlimmer, txtMarble, txtSlate; 83 | private JTextField txtName; 84 | 85 | private JCheckBox chkLand; 86 | 87 | @SuppressWarnings("rawtypes") 88 | private JComboBox cmbMapSize, cmbBiomeType; 89 | private Border compound, raisedbevel, loweredbevel; 90 | 91 | private JButton btnGenHeightMap, btnErodeHeightMap, btnDropDirt, btnSeedBiome, btnUndoBiome, btnResetBiomes, btnGenOres; 92 | private JButton btnResetHeightSeed, btnResetBiomeSeed; 93 | private JButton btnSaveActions, btnLoadActions, btnSaveImages, btnSaveMap, btnShowDump, btnShowTopo, btnShowCave, btnShowHeightMap; 94 | 95 | private ArrayList genHistory; 96 | 97 | private boolean apiClosed = true; 98 | 99 | @SuppressWarnings({ "unchecked", "rawtypes" }) 100 | public WGenerator(String title, int width, int height) { 101 | super(title); 102 | this.setDefaultCloseOperation(EXIT_ON_CLOSE); 103 | this.setLayout(new BorderLayout()); 104 | 105 | raisedbevel = BorderFactory.createRaisedBevelBorder(); 106 | loweredbevel = BorderFactory.createLoweredBevelBorder(); 107 | compound = BorderFactory.createCompoundBorder(raisedbevel, loweredbevel); 108 | 109 | pnlControls = new JPanel(); 110 | pnlControls.setLayout(new BoxLayout(pnlControls, BoxLayout.Y_AXIS)); 111 | pnlControls.setPreferredSize(new Dimension(400, 768)); 112 | pnlControls.setBorder(new EmptyBorder(10, 10, 10, 10)); 113 | 114 | pnlHeightMapControls = new JPanel(); 115 | pnlHeightMapControls.setLayout(new BorderLayout()); 116 | pnlHeightMapControls.setPreferredSize(new Dimension(380, 75)); 117 | pnlHeightMapControls.setBorder(compound); 118 | pnlHeightMapOptions = new JPanel(); 119 | pnlHeightMapOptions.setLayout(new FlowLayout(FlowLayout.CENTER)); 120 | pnlHeightMapOptions2 = new JPanel(); 121 | pnlHeightMapOptions2.setLayout(new FlowLayout(FlowLayout.CENTER)); 122 | pnlHeightMapOptionsMiddle = new JPanel(); 123 | pnlHeightMapOptionsMiddle.setLayout(new FlowLayout(FlowLayout.CENTER)); 124 | pnlHeightMapOptions3 = new JPanel(); 125 | pnlHeightMapOptions3.setLayout(new FlowLayout(FlowLayout.CENTER)); 126 | pnlHeightMapOptionsMiddleTop = new JPanel(); 127 | pnlHeightMapOptionsMiddleTop.setLayout(new FlowLayout(FlowLayout.CENTER)); 128 | pnlHeightMapOptionsMiddleBottom = new JPanel(); 129 | pnlHeightMapOptionsMiddleBottom.setLayout(new FlowLayout(FlowLayout.CENTER)); 130 | 131 | pnlErodeControls = new JPanel(); 132 | pnlErodeControls.setLayout(new BorderLayout()); 133 | pnlErodeControls.setPreferredSize(new Dimension(380, 30)); 134 | pnlErodeControls.setBorder(compound); 135 | pnlErodeOptions = new JPanel(); 136 | pnlErodeOptions.setLayout(new FlowLayout(FlowLayout.CENTER)); 137 | pnlErodeOptions2 = new JPanel(); 138 | pnlErodeOptions2.setLayout(new FlowLayout(FlowLayout.CENTER)); 139 | pnlErodeButton = new JPanel(); 140 | pnlErodeButton.setLayout(new FlowLayout(FlowLayout.CENTER)); 141 | 142 | pnlDirtControls = new JPanel(); 143 | pnlDirtControls.setLayout(new BorderLayout()); 144 | pnlDirtControls.setPreferredSize(new Dimension(380, 75)); 145 | pnlDirtControls.setBorder(compound); 146 | pnlDirtOptions = new JPanel(); 147 | pnlDirtOptions.setLayout(new FlowLayout(FlowLayout.CENTER)); 148 | pnlDirtOptions2 = new JPanel(); 149 | pnlDirtOptions2.setLayout(new FlowLayout(FlowLayout.CENTER)); 150 | pnlDirtOptions3 = new JPanel(); 151 | pnlDirtOptions3.setLayout(new FlowLayout(FlowLayout.CENTER)); 152 | pnlDirtOptionsMiddle = new JPanel(); 153 | pnlDirtOptionsMiddle.setLayout(new FlowLayout(FlowLayout.CENTER)); 154 | pnlDirtButton = new JPanel(); 155 | pnlDirtButton.setLayout(new FlowLayout(FlowLayout.CENTER)); 156 | 157 | pnlBiomeControls = new JPanel(); 158 | pnlBiomeControls.setLayout(new BorderLayout()); 159 | pnlBiomeControls.setPreferredSize(new Dimension(380, 75)); 160 | pnlBiomeControls.setBorder(compound); 161 | pnlBiomeOptions = new JPanel(); 162 | pnlBiomeOptions.setLayout(new FlowLayout(FlowLayout.CENTER)); 163 | pnlBiomeOptions2 = new JPanel(); 164 | pnlBiomeOptions2.setLayout(new FlowLayout(FlowLayout.CENTER)); 165 | pnlBiomeOptions3 = new JPanel(); 166 | pnlBiomeOptions3.setLayout(new FlowLayout(FlowLayout.CENTER)); 167 | pnlBiomeOptionsMiddle = new JPanel(); 168 | pnlBiomeOptionsMiddle.setLayout(new FlowLayout(FlowLayout.CENTER)); 169 | pnlBiomeButton = new JPanel(); 170 | pnlBiomeButton.setLayout(new FlowLayout(FlowLayout.CENTER)); 171 | 172 | pnlOreControls = new JPanel(); 173 | pnlOreControls.setLayout(new BorderLayout()); 174 | pnlOreControls.setPreferredSize(new Dimension(380, 110)); 175 | pnlOreControls.setBorder(compound); 176 | pnlOreOptions = new JPanel(); 177 | pnlOreOptions.setLayout(new FlowLayout(FlowLayout.CENTER)); 178 | pnlOreOptions2 = new JPanel(); 179 | pnlOreOptions2.setLayout(new FlowLayout(FlowLayout.CENTER)); 180 | pnlOreOptions3 = new JPanel(); 181 | pnlOreOptions3.setLayout(new FlowLayout(FlowLayout.CENTER)); 182 | pnlOreOptions4 = new JPanel(); 183 | pnlOreOptions4.setLayout(new FlowLayout(FlowLayout.CENTER)); 184 | pnlOreOptionsMiddle = new JPanel(); 185 | pnlOreOptionsMiddle.setLayout(new FlowLayout(FlowLayout.CENTER)); 186 | pnlOreButton = new JPanel(); 187 | pnlOreButton.setLayout(new FlowLayout(FlowLayout.CENTER)); 188 | 189 | pnlSaveControls = new JPanel(); 190 | pnlSaveControls.setLayout(new BoxLayout(pnlSaveControls, BoxLayout.Y_AXIS)); 191 | pnlSaveOptions = new JPanel(); 192 | pnlSaveOptions.setLayout(new FlowLayout(FlowLayout.CENTER)); 193 | 194 | lblMapSize = new JLabel("Map Size:"); 195 | cmbMapSize = new JComboBox(new Integer[] {1024, 2048, 4096, 8192, 16384}); 196 | cmbMapSize.setSelectedIndex(1); 197 | cmbMapSize.setEditable(false); 198 | 199 | lblSeed = new JLabel("Seed:"); 200 | txtSeed = new JTextField("" + System.currentTimeMillis(), 10); 201 | lblRes = new JLabel("Res:"); 202 | txtRes = new JTextField("" + (int) Constants.RESOLUTION, 3); 203 | lblIterations = new JLabel("Iterations:"); 204 | txtIterations = new JTextField("" + (int) Constants.HEIGHTMAP_ITERATIONS, 2); 205 | lblMinEdge = new JLabel("Min Edge:"); 206 | txtMinEdge = new JTextField("" + (int) Constants.MIN_EDGE, 3); 207 | lblBorderWeight = new JLabel("Border Weight:"); 208 | txtBorderWeight = new JTextField("" + (int) Constants.BORDER_WEIGHT, 2); 209 | lblMaxHeight = new JLabel("Max Height:"); 210 | txtMaxHeight = new JTextField("" + (int) Constants.MAP_HEIGHT, 3); 211 | chkLand = new JCheckBox("More Land", Constants.MORE_LAND); 212 | 213 | btnResetHeightSeed = new JButton("#"); 214 | btnResetHeightSeed.addActionListener(this); 215 | btnGenHeightMap = new JButton("Gen Heightmap"); 216 | btnGenHeightMap.addActionListener(this); 217 | 218 | pnlHeightMapOptions.add(lblMapSize); 219 | pnlHeightMapOptions.add(cmbMapSize); 220 | pnlHeightMapOptions.add(lblSeed); 221 | pnlHeightMapOptions.add(txtSeed); 222 | pnlHeightMapOptions.add(btnResetHeightSeed); 223 | pnlHeightMapOptionsMiddleTop.add(lblRes); 224 | pnlHeightMapOptionsMiddleTop.add(txtRes); 225 | pnlHeightMapOptionsMiddleTop.add(lblIterations); 226 | pnlHeightMapOptionsMiddleTop.add(txtIterations); 227 | pnlHeightMapOptionsMiddleBottom.add(lblMinEdge); 228 | pnlHeightMapOptionsMiddleBottom.add(txtMinEdge); 229 | pnlHeightMapOptionsMiddleBottom.add(lblBorderWeight); 230 | pnlHeightMapOptionsMiddleBottom.add(txtBorderWeight); 231 | pnlHeightMapOptionsMiddleBottom.add(lblMaxHeight); 232 | pnlHeightMapOptionsMiddleBottom.add(txtMaxHeight); 233 | pnlHeightMapOptions3.add(chkLand); 234 | pnlHeightMapOptions3.add(btnGenHeightMap); 235 | 236 | pnlHeightMapOptionsMiddle.add(pnlHeightMapOptionsMiddleTop); 237 | pnlHeightMapOptionsMiddle.add(pnlHeightMapOptionsMiddleBottom); 238 | 239 | pnlHeightMapControls.add(pnlHeightMapOptions, BorderLayout.NORTH); 240 | pnlHeightMapControls.add(pnlHeightMapOptionsMiddle, BorderLayout.CENTER); 241 | pnlHeightMapControls.add(pnlHeightMapOptions3, BorderLayout.SOUTH); 242 | 243 | lblErodeIterations = new JLabel("Erosion Iterations:"); 244 | txtErodeIterations = new JTextField("" + Constants.EROSION_ITERATIONS, 3); 245 | lblErodeMinSlope = new JLabel("Erosion Min Slope:"); 246 | txtErodeMinSlope = new JTextField("" + Constants.MIN_SLOPE, 3); 247 | lblErodeMaxSediment = new JLabel("Max Sediment Per Iteration:"); 248 | txtErodeMaxSediment = new JTextField("" + Constants.MAX_SEDIMENT, 3); 249 | 250 | btnErodeHeightMap = new JButton("Erode HeightMap"); 251 | btnErodeHeightMap.addActionListener(this); 252 | 253 | pnlErodeOptions.add(lblErodeIterations); 254 | pnlErodeOptions.add(txtErodeIterations); 255 | pnlErodeOptions.add(lblErodeMinSlope); 256 | pnlErodeOptions.add(txtErodeMinSlope); 257 | pnlErodeOptions2.add(lblErodeMaxSediment); 258 | pnlErodeOptions2.add(txtErodeMaxSediment); 259 | 260 | pnlErodeButton.add(btnErodeHeightMap); 261 | 262 | pnlErodeControls.add(pnlErodeOptions, BorderLayout.NORTH); 263 | pnlErodeControls.add(pnlErodeOptions2, BorderLayout.CENTER); 264 | pnlErodeControls.add(pnlErodeButton, BorderLayout.SOUTH); 265 | 266 | lblBiomeSeed = new JLabel("Biome Seed:"); 267 | txtBiomeSeed = new JTextField("" + System.currentTimeMillis(), 10); 268 | lblDirtAmnt = new JLabel("Dirt Per Tile:"); 269 | txtDirtAmnt = new JTextField("" + Constants.DIRT_DROP_COUNT, 3); 270 | lblDirtSlope = new JLabel("Max Dirt Slope:"); 271 | txtDirtSlope = new JTextField("" + Constants.MAX_DIRT_SLOPE, 3); 272 | lblDirtDiagSlope = new JLabel("Max Dirt Slope (Diagonal):"); 273 | txtDirtDiagSlope = new JTextField("" + Constants.MAX_DIRT_DIAG_SLOPE, 3); 274 | lblMaxDirtHeight = new JLabel("Max Dirt Height:"); 275 | txtMaxDirtHeight = new JTextField("" + Constants.ROCK_WEIGHT, 4); 276 | lblWaterHeight = new JLabel("Water Height:"); 277 | txtWaterHeight = new JTextField("" + Constants.WATER_HEIGHT, 4); 278 | 279 | btnResetBiomeSeed = new JButton("#"); 280 | btnResetBiomeSeed.addActionListener(this); 281 | btnDropDirt = new JButton("Drop Dirt"); 282 | btnDropDirt.addActionListener(this); 283 | 284 | pnlDirtOptions.add(lblBiomeSeed); 285 | pnlDirtOptions.add(txtBiomeSeed); 286 | pnlDirtOptions.add(btnResetBiomeSeed); 287 | pnlDirtOptions.add(lblDirtAmnt); 288 | pnlDirtOptions.add(txtDirtAmnt); 289 | pnlDirtOptions2.add(lblDirtSlope); 290 | pnlDirtOptions2.add(txtDirtSlope); 291 | pnlDirtOptions2.add(lblDirtDiagSlope); 292 | pnlDirtOptions2.add(txtDirtDiagSlope); 293 | pnlDirtOptions3.add(lblMaxDirtHeight); 294 | pnlDirtOptions3.add(txtMaxDirtHeight); 295 | pnlDirtOptions3.add(lblWaterHeight); 296 | pnlDirtOptions3.add(txtWaterHeight); 297 | 298 | pnlDirtOptionsMiddle.add(pnlDirtOptions2); 299 | pnlDirtOptionsMiddle.add(pnlDirtOptions3); 300 | 301 | pnlDirtButton.add(btnDropDirt); 302 | 303 | pnlDirtControls.add(pnlDirtOptions, BorderLayout.NORTH); 304 | pnlDirtControls.add(pnlDirtOptionsMiddle, BorderLayout.CENTER); 305 | pnlDirtControls.add(pnlDirtButton, BorderLayout.SOUTH); 306 | 307 | btnSeedBiome = new JButton("Add Biome"); 308 | btnSeedBiome.addActionListener(this); 309 | btnUndoBiome = new JButton("Undo Last Biome"); 310 | btnUndoBiome.addActionListener(this); 311 | btnResetBiomes = new JButton("Reset Biomes"); 312 | btnResetBiomes.addActionListener(this); 313 | 314 | cmbBiomeType = new JComboBox(new Tile[] { Tile.TILE_CLAY, Tile.TILE_DIRT, Tile.TILE_DIRT_PACKED, Tile.TILE_GRASS, Tile.TILE_GRAVEL, Tile.TILE_KELP, 315 | Tile.TILE_LAVA, Tile.TILE_MARSH, Tile.TILE_MOSS, Tile.TILE_MYCELIUM, Tile.TILE_PEAT, Tile.TILE_REED, Tile.TILE_SAND, Tile.TILE_STEPPE, 316 | Tile.TILE_TAR, Tile.TILE_TUNDRA, Tile.TILE_TREE_APPLE, Tile.TILE_TREE_BIRCH, Tile.TILE_TREE_CEDAR, Tile.TILE_TREE_CHERRY, Tile.TILE_TREE_CHESTNUT, 317 | Tile.TILE_TREE_FIR, Tile.TILE_TREE_LEMON, Tile.TILE_TREE_LINDEN, Tile.TILE_TREE_MAPLE, Tile.TILE_TREE_OAK, Tile.TILE_TREE_OLIVE, Tile.TILE_TREE_PINE, 318 | Tile.TILE_TREE_WALNUT, Tile.TILE_TREE_WILLOW, Tile.TILE_BUSH_CAMELLIA, Tile.TILE_BUSH_GRAPE, Tile.TILE_BUSH_LAVENDER, Tile.TILE_BUSH_OLEANDER, 319 | Tile.TILE_BUSH_ROSE, Tile.TILE_BUSH_THORN 320 | }); 321 | cmbBiomeType.setSelectedIndex(12); // 12 = SAND 322 | cmbBiomeType.setEditable(false); 323 | 324 | lblBiomeSeedCount = new JLabel("Seed Count:"); 325 | txtBiomeSeedCount = new JTextField("" + Constants.BIOME_SEEDS, 3); 326 | lblBiomeSize = new JLabel("Size:"); 327 | txtBiomeSize = new JTextField("" + Constants.BIOME_SIZE, 3); 328 | lblBiomeMaxSlope = new JLabel("Max Slope:"); 329 | txtBiomeMaxSlope = new JTextField("" + Constants.BIOME_MAX_SLOPE, 3); 330 | lblBiomeRate = new JLabel("Growth % N/S/E/W:"); 331 | txtBiomeRateN = new JTextField("" + Constants.BIOME_RATE / 2, 2); 332 | txtBiomeRateS = new JTextField("" + (int) (Constants.BIOME_RATE * 1.3), 2); 333 | txtBiomeRateE = new JTextField("" + (int) (Constants.BIOME_RATE * 0.6), 2); 334 | txtBiomeRateW = new JTextField("" + Constants.BIOME_RATE, 2); 335 | lblBiomeMinHeight = new JLabel("Min Height:"); 336 | txtBiomeMinHeight = new JTextField("" + Constants.BIOME_MIN_HEIGHT, 4); 337 | lblBiomeMaxHeight = new JLabel("Max Height:"); 338 | txtBiomeMaxHeight = new JTextField("" + Constants.BIOME_MAX_HEIGHT, 4); 339 | 340 | pnlBiomeOptions.add(cmbBiomeType); 341 | pnlBiomeOptions.add(lblBiomeSeedCount); 342 | pnlBiomeOptions.add(txtBiomeSeedCount); 343 | pnlBiomeOptions.add(lblBiomeSize); 344 | pnlBiomeOptions.add(txtBiomeSize); 345 | pnlBiomeOptions2.add(lblBiomeMaxSlope); 346 | pnlBiomeOptions2.add(txtBiomeMaxSlope); 347 | pnlBiomeOptions3.add(lblBiomeRate); 348 | pnlBiomeOptions3.add(txtBiomeRateN); 349 | pnlBiomeOptions3.add(txtBiomeRateS); 350 | pnlBiomeOptions3.add(txtBiomeRateE); 351 | pnlBiomeOptions3.add(txtBiomeRateW); 352 | pnlBiomeOptions2.add(lblBiomeMinHeight); 353 | pnlBiomeOptions2.add(txtBiomeMinHeight); 354 | pnlBiomeOptions2.add(lblBiomeMaxHeight); 355 | pnlBiomeOptions2.add(txtBiomeMaxHeight); 356 | 357 | pnlBiomeOptionsMiddle.add(pnlBiomeOptions2); 358 | pnlBiomeOptionsMiddle.add(pnlBiomeOptions3); 359 | 360 | pnlBiomeButton.add(btnSeedBiome); 361 | pnlBiomeButton.add(btnUndoBiome); 362 | pnlBiomeButton.add(btnResetBiomes); 363 | 364 | pnlBiomeControls.add(pnlBiomeOptions, BorderLayout.NORTH); 365 | pnlBiomeControls.add(pnlBiomeOptionsMiddle, BorderLayout.CENTER); 366 | pnlBiomeControls.add(pnlBiomeButton, BorderLayout.SOUTH); 367 | 368 | btnGenOres = new JButton("Generate Ores"); 369 | btnGenOres.addActionListener(this); 370 | 371 | lblIron = new JLabel("Iron %:"); 372 | lblGold = new JLabel("Gold %:"); 373 | lblSilver = new JLabel("Silver %:"); 374 | lblZinc = new JLabel("Zinc %:"); 375 | lblCopper = new JLabel("Copper %:"); 376 | lblLead = new JLabel("Lead %:"); 377 | lblTin = new JLabel("Tin %:"); 378 | lblAddy = new JLabel("Addy %:"); 379 | lblGlimmer = new JLabel("Glimmer %:"); 380 | lblMarble = new JLabel("Marble %:"); 381 | lblSlate = new JLabel("Slate %:"); 382 | lblRock = new JLabel("Rock %:"); 383 | 384 | txtIron = new JTextField("" + Constants.ORE_IRON, 3); 385 | txtIron.addFocusListener(this); 386 | txtGold = new JTextField("" + Constants.ORE_GOLD, 3); 387 | txtGold.addFocusListener(this); 388 | txtSilver = new JTextField("" + Constants.ORE_SILVER, 3); 389 | txtSilver.addFocusListener(this); 390 | txtZinc = new JTextField("" + Constants.ORE_ZINC, 3); 391 | txtZinc.addFocusListener(this); 392 | txtCopper = new JTextField("" + Constants.ORE_COPPER, 3); 393 | txtCopper.addFocusListener(this); 394 | txtLead = new JTextField("" + Constants.ORE_LEAD, 3); 395 | txtLead.addFocusListener(this); 396 | txtTin = new JTextField("" + Constants.ORE_TIN, 3); 397 | txtTin.addFocusListener(this); 398 | txtAddy = new JTextField("" + Constants.ORE_ADDY, 3); 399 | txtAddy.addFocusListener(this); 400 | txtGlimmer = new JTextField("" + Constants.ORE_GLIMMER, 3); 401 | txtGlimmer.addFocusListener(this); 402 | txtMarble = new JTextField("" + Constants.ORE_MARBLE, 3); 403 | txtMarble.addFocusListener(this); 404 | txtSlate = new JTextField("" + Constants.ORE_SLATE, 3); 405 | txtSlate.addFocusListener(this); 406 | txtRock = new JTextField("" + Constants.ORE_ROCK, 3); 407 | txtRock.setEditable(false); 408 | 409 | pnlOreOptions.add(lblIron); 410 | pnlOreOptions.add(txtIron); 411 | pnlOreOptions.add(lblGold); 412 | pnlOreOptions.add(txtGold); 413 | pnlOreOptions.add(lblSilver); 414 | pnlOreOptions.add(txtSilver); 415 | pnlOreOptions2.add(lblZinc); 416 | pnlOreOptions2.add(txtZinc); 417 | pnlOreOptions2.add(lblCopper); 418 | pnlOreOptions2.add(txtCopper); 419 | pnlOreOptions2.add(lblLead); 420 | pnlOreOptions2.add(txtLead); 421 | pnlOreOptions3.add(lblTin); 422 | pnlOreOptions3.add(txtTin); 423 | pnlOreOptions4.add(lblAddy); 424 | pnlOreOptions4.add(txtAddy); 425 | pnlOreOptions4.add(lblGlimmer); 426 | pnlOreOptions4.add(txtGlimmer); 427 | pnlOreOptions3.add(lblMarble); 428 | pnlOreOptions3.add(txtMarble); 429 | pnlOreOptions3.add(lblSlate); 430 | pnlOreOptions3.add(txtSlate); 431 | pnlOreOptions4.add(lblRock); 432 | pnlOreOptions4.add(txtRock); 433 | 434 | pnlOreOptionsMiddle.add(pnlOreOptions2); 435 | pnlOreOptionsMiddle.add(pnlOreOptions3); 436 | pnlOreOptionsMiddle.add(pnlOreOptions4); 437 | 438 | pnlOreButton.add(btnGenOres); 439 | 440 | pnlOreControls.add(pnlOreOptions, BorderLayout.NORTH); 441 | pnlOreControls.add(pnlOreOptionsMiddle, BorderLayout.CENTER); 442 | pnlOreControls.add(pnlOreButton, BorderLayout.SOUTH); 443 | 444 | txtName = new JTextField(txtSeed.getText(), 10); 445 | txtName.addFocusListener(this); 446 | btnSaveActions = new JButton("Save Actions"); 447 | btnSaveActions.addActionListener(this); 448 | btnLoadActions = new JButton("Load Actions"); 449 | btnLoadActions.addActionListener(this); 450 | btnSaveImages = new JButton("Save Image Dumps"); 451 | btnSaveImages.addActionListener(this); 452 | btnSaveMap = new JButton("Save Map Files"); 453 | btnSaveMap.addActionListener(this); 454 | btnShowDump = new JButton("Show Map View"); 455 | btnShowDump.addActionListener(this); 456 | btnShowTopo = new JButton("Show Topo View"); 457 | btnShowTopo.addActionListener(this); 458 | btnShowCave = new JButton("Show Cave View"); 459 | btnShowCave.addActionListener(this); 460 | btnShowHeightMap = new JButton("Show Height View"); 461 | btnShowHeightMap.addActionListener(this); 462 | 463 | pnlSaveOptions.add(txtName); 464 | pnlSaveOptions.add(btnSaveActions); 465 | pnlSaveOptions.add(btnLoadActions); 466 | pnlSaveOptions.add(btnSaveImages); 467 | pnlSaveOptions.add(btnSaveMap); 468 | pnlSaveOptions.add(btnShowDump); 469 | pnlSaveOptions.add(btnShowTopo); 470 | pnlSaveOptions.add(btnShowCave); 471 | pnlSaveOptions.add(btnShowHeightMap); 472 | 473 | pnlSaveControls.add(pnlSaveOptions, BorderLayout.CENTER); 474 | pnlSaveControls.setPreferredSize(new Dimension(1000, 35)); 475 | 476 | pnlControls.add(pnlHeightMapControls); 477 | pnlControls.add(pnlErodeControls); 478 | pnlControls.add(pnlDirtControls); 479 | pnlControls.add(pnlBiomeControls); 480 | pnlControls.add(pnlOreControls); 481 | 482 | pnlMap = new MapPanel(width, height); 483 | pnlMap.setBackground(Color.BLACK); 484 | 485 | this.add(pnlControls, BorderLayout.EAST); 486 | this.add(pnlMap, BorderLayout.CENTER); 487 | this.add(pnlSaveControls, BorderLayout.SOUTH); 488 | 489 | this.setBounds(0, 0, width + 400, height + 35); 490 | this.setLocationRelativeTo(null); 491 | this.setVisible(true); 492 | } 493 | 494 | public WurmAPI getAPI() { 495 | if (apiClosed) 496 | api = null; 497 | 498 | if (api == null) 499 | try { 500 | api = WurmAPI.create("./maps/" + txtName.getText() + "/", (int) (Math.log(heightMap.getMapSize()) / Math.log(2))); 501 | apiClosed = false; 502 | } catch (IOException e) { 503 | e.printStackTrace(); 504 | } 505 | 506 | return api; 507 | } 508 | 509 | public void newHeightMap(long seed, int mapSize, double resolution, int iterations, int minEdge, double borderWeight, int maxHeight, boolean moreLand) { 510 | heightMap = new HeightMap(seed, mapSize, resolution, iterations, minEdge, borderWeight, maxHeight, moreLand); 511 | heightMap.generateHeights(); 512 | 513 | updateMapView(false, 0); 514 | } 515 | 516 | public void updateMapView(boolean apiView, int viewType) { 517 | if (!apiView) { 518 | Graphics g = pnlMap.getMapImage().getGraphics(); 519 | 520 | for (int i = 0; i < heightMap.getMapSize(); i++) { 521 | for (int j = 0; j < heightMap.getMapSize(); j++) { 522 | g.setColor(new Color((float) heightMap.getHeight(i, j), (float) heightMap.getHeight(i, j), (float) heightMap.getHeight(i, j))); 523 | g.fillRect(i, j, 1, 1); 524 | } 525 | } 526 | } else { 527 | updateAPIMap(); 528 | 529 | if (viewType == 1) 530 | pnlMap.setMapImage(getAPI().getMapData().createTopographicDump(true, (short) 250)); 531 | else if (viewType == 2) 532 | pnlMap.setMapImage(getAPI().getMapData().createCaveDump(true)); 533 | else 534 | pnlMap.setMapImage(getAPI().getMapData().createMapDump()); 535 | } 536 | 537 | pnlMap.updateScale(); 538 | pnlMap.checkBounds(); 539 | pnlMap.repaint(); 540 | } 541 | 542 | private void updateAPIMap() { 543 | MapData map = getAPI().getMapData(); 544 | Random treeRand = new Random(System.currentTimeMillis()); 545 | 546 | for (int i = 0; i < heightMap.getMapSize(); i++) { 547 | for (int j = 0; j < heightMap.getMapSize(); j++) { 548 | map.setSurfaceHeight(i, j, tileMap.getSurfaceHeight(i, j)); 549 | map.setRockHeight(i, j, tileMap.getRockHeight(i, j)); 550 | 551 | if (tileMap.hasOres()) 552 | map.setCaveTile(i, j, tileMap.getOreType(i, j), tileMap.getOreCount(i, j)); 553 | 554 | if (tileMap.getType(i, j).isTree()) 555 | map.setTree(i, j, tileMap.getType(i, j).getTreeType((byte) 0), 556 | FoliageAge.values()[treeRand.nextInt(FoliageAge.values().length)], GrowthTreeStage.MEDIUM); 557 | else if (tileMap.getType(i, j).isBush()) 558 | map.setBush(i, j, tileMap.getType(i, j).getBushType((byte) 0), 559 | FoliageAge.values()[treeRand.nextInt(FoliageAge.values().length)], GrowthTreeStage.MEDIUM); 560 | else 561 | map.setSurfaceTile(i, j, tileMap.getType(i, j)); 562 | } 563 | } 564 | } 565 | 566 | private void parseAction(String action) { 567 | String[] parts = action.split(":"); 568 | if (parts.length < 2) 569 | return; 570 | 571 | String[] options = parts[1].split(","); 572 | switch (parts[0]) { 573 | case "HEIGHTMAP": 574 | if (options.length < 8) { 575 | JOptionPane.showMessageDialog(this, "Not enough options for HEIGHTMAP", "Error Loading Actions", JOptionPane.ERROR_MESSAGE); 576 | return; 577 | } 578 | 579 | try { 580 | txtSeed.setText(options[0]); 581 | cmbMapSize.setSelectedIndex(Integer.parseInt(options[1])); 582 | txtRes.setText(options[2]); 583 | txtIterations.setText(options[3]); 584 | txtMinEdge.setText(options[4]); 585 | txtBorderWeight.setText(options[5]); 586 | txtMaxHeight.setText(options[6]); 587 | chkLand.setSelected(Boolean.parseBoolean(options[7])); 588 | 589 | btnGenHeightMap.doClick(); 590 | } catch (Exception nfe) { 591 | JOptionPane.showMessageDialog(this, "Error parsing number " + nfe.getMessage().toLowerCase(), "Error Loading Actions", JOptionPane.ERROR_MESSAGE); 592 | } 593 | break; 594 | case "ERODE": 595 | if (options.length < 3) { 596 | JOptionPane.showMessageDialog(this, "Not enough options for ERODE", "Error Loading Actions", JOptionPane.ERROR_MESSAGE); 597 | return; 598 | } 599 | 600 | txtErodeIterations.setText(options[0]); 601 | txtErodeMinSlope.setText(options[1]); 602 | txtErodeMaxSediment.setText(options[2]); 603 | 604 | btnErodeHeightMap.doClick(); 605 | break; 606 | case "DROPDIRT": 607 | if (options.length < 6) { 608 | JOptionPane.showMessageDialog(this, "Not enough options for DROPDIRT", "Error Loading Actions", JOptionPane.ERROR_MESSAGE); 609 | return; 610 | } 611 | 612 | txtBiomeSeed.setText(options[0]); 613 | txtWaterHeight.setText(options[1]); 614 | txtDirtAmnt.setText(options[2]); 615 | txtDirtSlope.setText(options[3]); 616 | txtDirtDiagSlope.setText(options[4]); 617 | txtMaxDirtHeight.setText(options[5]); 618 | 619 | btnDropDirt.doClick(); 620 | break; 621 | case "UNDOBIOME": 622 | btnUndoBiome.doClick(); 623 | break; 624 | case "RESETBIOMES": 625 | btnResetBiomes.doClick(); 626 | break; 627 | case "GENORES": 628 | if (options.length < 12) { 629 | JOptionPane.showMessageDialog(this, "Not enough options for GENORES", "Error Loading Actions", JOptionPane.ERROR_MESSAGE); 630 | return; 631 | } 632 | 633 | txtRock.setText(options[0]); 634 | txtIron.setText(options[1]); 635 | txtGold.setText(options[2]); 636 | txtSilver.setText(options[3]); 637 | txtZinc.setText(options[4]); 638 | txtCopper.setText(options[5]); 639 | txtLead.setText(options[6]); 640 | txtTin.setText(options[7]); 641 | txtAddy.setText(options[8]); 642 | txtGlimmer.setText(options[9]); 643 | txtMarble.setText(options[10]); 644 | txtSlate.setText(options[11]); 645 | 646 | btnGenOres.doClick(); 647 | break; 648 | default: 649 | if(parts[0].startsWith("SEEDBIOME")){ 650 | if (options.length < 10) { 651 | JOptionPane.showMessageDialog(this, "Not enough options for SEEDBIOME", "Error Loading Actions", JOptionPane.ERROR_MESSAGE); 652 | return; 653 | } 654 | 655 | try { 656 | cmbBiomeType.setSelectedIndex(Integer.parseInt(options[0])); 657 | txtBiomeSeedCount.setText(options[1]); 658 | txtBiomeSize.setText(options[2]); 659 | txtBiomeMaxSlope.setText(options[3]); 660 | txtBiomeRateN.setText(options[4]); 661 | txtBiomeRateS.setText(options[5]); 662 | txtBiomeRateE.setText(options[6]); 663 | txtBiomeRateW.setText(options[7]); 664 | txtBiomeMinHeight.setText(options[8]); 665 | txtBiomeMaxHeight.setText(options[9]); 666 | 667 | btnSeedBiome.doClick(); 668 | } catch (Exception nfe) { 669 | JOptionPane.showMessageDialog(this, "Error parsing number " + nfe.getMessage().toLowerCase(), "Error Loading Actions", JOptionPane.ERROR_MESSAGE); 670 | } 671 | } 672 | break; 673 | } 674 | } 675 | 676 | @Override 677 | public void actionPerformed(ActionEvent e) { 678 | if (e.getSource() == btnGenHeightMap) { 679 | try { 680 | api = null; 681 | genHistory = new ArrayList(); 682 | 683 | pnlMap.setMapSize((int) cmbMapSize.getSelectedItem()); 684 | 685 | newHeightMap(txtSeed.getText().hashCode(), (int) cmbMapSize.getSelectedItem(), 686 | Double.parseDouble(txtRes.getText()), Integer.parseInt(txtIterations.getText()), 687 | Integer.parseInt(txtMinEdge.getText()), Double.parseDouble(txtBorderWeight.getText()), 688 | Integer.parseInt(txtMaxHeight.getText()), chkLand.isSelected()); 689 | 690 | genHistory.add("HEIGHTMAP:" + txtSeed.getText() + "," + cmbMapSize.getSelectedIndex() + "," + txtRes.getText() + "," + 691 | txtIterations.getText() + "," + txtMinEdge.getText() + "," + txtBorderWeight.getText() + "," + 692 | txtMaxHeight.getText() + "," + chkLand.isSelected()); 693 | } catch (NumberFormatException nfe) { 694 | JOptionPane.showMessageDialog(this, "Error parsing number " + nfe.getMessage().toLowerCase(), "Error Generating HeightMap", JOptionPane.ERROR_MESSAGE); 695 | } 696 | } 697 | 698 | if (e.getSource() == btnErodeHeightMap) { 699 | if (heightMap == null) { 700 | JOptionPane.showMessageDialog(this, "HeightMap does not exist", "Error Eroding HeightMap", JOptionPane.ERROR_MESSAGE); 701 | return; 702 | } 703 | 704 | try { 705 | heightMap.erode(Integer.parseInt(txtErodeIterations.getText()), Integer.parseInt(txtErodeMinSlope.getText()), 706 | Integer.parseInt(txtErodeMaxSediment.getText())); 707 | 708 | updateMapView(false, 0); 709 | 710 | genHistory.add("ERODE:" + txtErodeIterations.getText() + "," + txtErodeMinSlope.getText() + "," + txtErodeMaxSediment.getText()); 711 | } catch (NumberFormatException nfe) { 712 | JOptionPane.showMessageDialog(this, "Error parsing number " + nfe.getMessage().toLowerCase(), "Error Eroding HeightMap", JOptionPane.ERROR_MESSAGE); 713 | } 714 | } 715 | 716 | if (e.getSource() == btnDropDirt) { 717 | if (heightMap == null) { 718 | JOptionPane.showMessageDialog(this, "HeightMap does not exist", "Error Dropping Dirt", JOptionPane.ERROR_MESSAGE); 719 | return; 720 | } 721 | 722 | try { 723 | tileMap = new TileMap(heightMap); 724 | tileMap.setBiomeSeed(txtBiomeSeed.getText().hashCode()); 725 | tileMap.setWaterHeight(Integer.parseInt(txtWaterHeight.getText())); 726 | tileMap.dropDirt(Integer.parseInt(txtDirtAmnt.getText()), Integer.parseInt(txtDirtSlope.getText()), 727 | Integer.parseInt(txtDirtDiagSlope.getText()), Integer.parseInt(txtMaxDirtHeight.getText())); 728 | 729 | updateMapView(true, 0); 730 | 731 | genHistory.add("DROPDIRT:" + txtBiomeSeed.getText() + "," + txtWaterHeight.getText() + "," + txtDirtAmnt.getText() + "," + 732 | txtDirtSlope.getText() + "," + txtDirtDiagSlope.getText() + "," + txtMaxDirtHeight.getText()); 733 | } catch (NumberFormatException nfe) { 734 | JOptionPane.showMessageDialog(this, "Error parsing number " + nfe.getMessage().toLowerCase(), "Error Dropping Dirt", JOptionPane.ERROR_MESSAGE); 735 | } 736 | } 737 | 738 | if (e.getSource() == btnSeedBiome) { 739 | if (tileMap == null) { 740 | JOptionPane.showMessageDialog(this, "TileMap does not exist - Add Dirt first", "Error Adding Biome", JOptionPane.ERROR_MESSAGE); 741 | return; 742 | } 743 | 744 | try { 745 | double[] rates = new double[4]; 746 | 747 | rates[0] = Integer.parseInt(txtBiomeRateN.getText()) / 100.0; 748 | rates[1] = Integer.parseInt(txtBiomeRateS.getText()) / 100.0; 749 | rates[2] = Integer.parseInt(txtBiomeRateE.getText()) / 100.0; 750 | rates[3] = Integer.parseInt(txtBiomeRateW.getText()) / 100.0; 751 | 752 | tileMap.plantBiome(Integer.parseInt(txtBiomeSeedCount.getText()), Integer.parseInt(txtBiomeSize.getText()), 753 | rates, Integer.parseInt(txtBiomeMaxSlope.getText()), Integer.parseInt(txtBiomeMinHeight.getText()), 754 | Integer.parseInt(txtBiomeMaxHeight.getText()), (Tile) cmbBiomeType.getSelectedItem()); 755 | 756 | updateMapView(true, 0); 757 | 758 | genHistory.add("SEEDBIOME("+cmbBiomeType.getSelectedItem()+"):" + cmbBiomeType.getSelectedIndex() + "," + txtBiomeSeedCount.getText() + "," + txtBiomeSize.getText() + "," + 759 | txtBiomeMaxSlope.getText() + "," + txtBiomeRateN.getText() + "," + txtBiomeRateS.getText() + "," + 760 | txtBiomeRateE.getText() + "," + txtBiomeRateW.getText() + "," + txtBiomeMinHeight.getText() + "," + 761 | txtBiomeMaxHeight.getText()); 762 | } catch (NumberFormatException nfe) { 763 | JOptionPane.showMessageDialog(this, "Error parsing number " + nfe.getMessage().toLowerCase(), "Error Dropping Dirt", JOptionPane.ERROR_MESSAGE); 764 | } 765 | } 766 | 767 | if (e.getSource() == btnUndoBiome) { 768 | if (tileMap == null) { 769 | JOptionPane.showMessageDialog(this, "TileMap does not exist - Add Dirt first", "Error Resetting Biomes", JOptionPane.ERROR_MESSAGE); 770 | return; 771 | } 772 | 773 | tileMap.undoLastBiome(); 774 | 775 | updateMapView(true, 0); 776 | 777 | genHistory.add("UNDOBIOME:null"); 778 | } 779 | 780 | if (e.getSource() == btnResetBiomes) { 781 | if (tileMap == null) { 782 | JOptionPane.showMessageDialog(this, "TileMap does not exist - Add Dirt first", "Error Resetting Biomes", JOptionPane.ERROR_MESSAGE); 783 | return; 784 | } 785 | 786 | for (int i = 0; i < heightMap.getMapSize(); i++) { 787 | for (int j = 0; j < heightMap.getMapSize(); j++) { 788 | tileMap.addDirt(i, j, 0); 789 | } 790 | } 791 | 792 | updateMapView(true, 0); 793 | 794 | genHistory.add("RESETBIOMES:null"); 795 | } 796 | 797 | if (e.getSource() == btnGenOres) { 798 | if (tileMap == null) { 799 | JOptionPane.showMessageDialog(this, "TileMap does not exist - Add Dirt first", "Error Resetting Biomes", JOptionPane.ERROR_MESSAGE); 800 | return; 801 | } 802 | 803 | try { 804 | double[] rates = { Double.parseDouble(txtRock.getText()), Double.parseDouble(txtIron.getText()), Double.parseDouble(txtGold.getText()), 805 | Double.parseDouble(txtSilver.getText()), Double.parseDouble(txtZinc.getText()), Double.parseDouble(txtCopper.getText()), 806 | Double.parseDouble(txtLead.getText()), Double.parseDouble(txtTin.getText()), Double.parseDouble(txtAddy.getText()), 807 | Double.parseDouble(txtGlimmer.getText()), Double.parseDouble(txtMarble.getText()), Double.parseDouble(txtSlate.getText()) 808 | }; 809 | 810 | tileMap.generateOres(rates); 811 | 812 | updateAPIMap(); 813 | 814 | updateMapView(true, 2); 815 | 816 | genHistory.add("GENORES:" + txtRock.getText() + "," + txtIron.getText() + "," + txtGold.getText() + "," + 817 | txtSilver.getText() + "," + txtZinc.getText() + "," + txtCopper.getText() + "," + 818 | txtLead.getText() + "," + txtTin.getText() + "," + txtAddy.getText() + "," + 819 | txtGlimmer.getText() + "," + txtMarble.getText() + "," + txtSlate.getText()); 820 | } catch (NumberFormatException nfe) { 821 | JOptionPane.showMessageDialog(this, "Error parsing number " + nfe.getMessage().toLowerCase(), "Error Generating Ores", JOptionPane.ERROR_MESSAGE); 822 | } 823 | } 824 | 825 | if (e.getSource() == btnShowDump) { 826 | if (tileMap == null) { 827 | JOptionPane.showMessageDialog(this, "TileMap does not exist - Add Dirt first", "Error Showing Map", JOptionPane.ERROR_MESSAGE); 828 | return; 829 | } 830 | 831 | updateMapView(true, 0); 832 | } 833 | 834 | if (e.getSource() == btnShowTopo) { 835 | if (tileMap == null) { 836 | JOptionPane.showMessageDialog(this, "TileMap does not exist - Add Dirt first", "Error Showing Map", JOptionPane.ERROR_MESSAGE); 837 | return; 838 | } 839 | 840 | updateMapView(true, 1); 841 | } 842 | 843 | if (e.getSource() == btnShowCave) { 844 | if (tileMap == null) { 845 | JOptionPane.showMessageDialog(this, "TileMap does not exist - Add Dirt first", "Error Showing Map", JOptionPane.ERROR_MESSAGE); 846 | return; 847 | } 848 | 849 | if (!tileMap.hasOres()) { 850 | JOptionPane.showMessageDialog(this, "No Cave Map - Generate Ores first", "Error Showing Map", JOptionPane.ERROR_MESSAGE); 851 | return; 852 | } 853 | 854 | updateMapView(true, 2); 855 | } 856 | 857 | if (e.getSource() == btnShowHeightMap) { 858 | if (heightMap == null) { 859 | JOptionPane.showMessageDialog(this, "HeightMap does not exist", "Error Showing Map", JOptionPane.ERROR_MESSAGE); 860 | return; 861 | } 862 | 863 | updateMapView(false, 0); 864 | } 865 | 866 | if (e.getSource() == btnSaveImages) { 867 | if (tileMap == null) { 868 | JOptionPane.showMessageDialog(this, "TileMap does not exist - Add Dirt first", "Error Saving Images", JOptionPane.ERROR_MESSAGE); 869 | return; 870 | } 871 | 872 | updateAPIMap(); 873 | 874 | MapData map = getAPI().getMapData(); 875 | try { 876 | ImageIO.write(map.createMapDump(), "png", new File("./maps/" + txtName.getText() + "/map.png")); 877 | ImageIO.write(map.createTopographicDump(true, (short) 250), "png", new File("./maps/" + txtName.getText() + "/topography.png")); 878 | ImageIO.write(map.createCaveDump(true), "png", new File("./maps/" + txtName.getText() + "/cave.png")); 879 | } catch (IOException ex) { 880 | logger.log(Level.SEVERE, null, ex); 881 | } 882 | } 883 | 884 | if (e.getSource() == btnSaveMap) { 885 | if (tileMap == null) { 886 | JOptionPane.showMessageDialog(this, "TileMap does not exist - Add Dirt first", "Error Saving Map", JOptionPane.ERROR_MESSAGE); 887 | return; 888 | } 889 | 890 | updateAPIMap(); 891 | 892 | getAPI().getMapData().saveChanges(); 893 | getAPI().close(); 894 | apiClosed = true; 895 | } 896 | 897 | if (e.getSource() == btnSaveActions) { 898 | if (tileMap == null) { 899 | JOptionPane.showMessageDialog(this, "TileMap does not exist - Add Dirt first", "Error Saving Map", JOptionPane.ERROR_MESSAGE); 900 | return; 901 | } 902 | 903 | try { 904 | File actionsFile = new File("./maps/" + txtName.getText() + "/map_actions.txt"); 905 | actionsFile.createNewFile(); 906 | 907 | BufferedWriter bw = new BufferedWriter(new FileWriter(actionsFile)); 908 | for (String s : genHistory) 909 | bw.write(s + "\r\n"); 910 | 911 | bw.close(); 912 | } catch (IOException ex) { 913 | logger.log(Level.SEVERE, null, ex); 914 | } 915 | } 916 | 917 | if (e.getSource() == btnLoadActions) { 918 | try { 919 | File actionsFile; 920 | 921 | JFileChooser fc = new JFileChooser(); 922 | fc.addChoosableFileFilter(new TextFileView()); 923 | fc.setAcceptAllFileFilterUsed(false); 924 | fc.setCurrentDirectory(new File("./maps/")); 925 | 926 | int returnVal = fc.showDialog(this, "Load Actions"); 927 | 928 | if (returnVal == JFileChooser.APPROVE_OPTION) { 929 | actionsFile = fc.getSelectedFile(); 930 | txtName.setText(actionsFile.getParentFile().getName()); 931 | 932 | BufferedReader br = new BufferedReader(new FileReader(actionsFile)); 933 | String line; 934 | while ((line = br.readLine()) != null) { 935 | parseAction(line); 936 | } 937 | 938 | br.close(); 939 | } 940 | } catch (IOException ex) { 941 | JOptionPane.showMessageDialog(this, "Unable to load actions file", "Error Loading Map", JOptionPane.ERROR_MESSAGE); 942 | logger.log(Level.WARNING, "Error loading actions file: " + ex.getMessage()); 943 | } 944 | } 945 | 946 | if (e.getSource() == btnResetHeightSeed) { 947 | txtSeed.setText("" + System.currentTimeMillis()); 948 | } 949 | 950 | if (e.getSource() == btnResetBiomeSeed) { 951 | txtBiomeSeed.setText("" + System.currentTimeMillis()); 952 | } 953 | } 954 | 955 | public static void main(String[] args) { 956 | new WGenerator(Constants.WINDOW_TITLE, Constants.WINDOW_SIZE, Constants.WINDOW_SIZE); 957 | } 958 | 959 | @Override 960 | public void focusGained(FocusEvent e) { 961 | // Do Nothing 962 | } 963 | 964 | @Override 965 | public void focusLost(FocusEvent e) { 966 | if (e.getSource() instanceof JTextField) { 967 | if (e.getSource() == txtName) { 968 | if (!apiClosed) 969 | getAPI().close(); 970 | 971 | apiClosed = true; 972 | updateAPIMap(); 973 | } else { 974 | try { 975 | double[] rates = { Double.parseDouble(txtIron.getText()), Double.parseDouble(txtGold.getText()), 976 | Double.parseDouble(txtSilver.getText()), Double.parseDouble(txtZinc.getText()), Double.parseDouble(txtCopper.getText()), 977 | Double.parseDouble(txtLead.getText()), Double.parseDouble(txtTin.getText()), Double.parseDouble(txtAddy.getText()), 978 | Double.parseDouble(txtGlimmer.getText()), Double.parseDouble(txtMarble.getText()), Double.parseDouble(txtSlate.getText()) 979 | }; 980 | 981 | double total = 0; 982 | for (int i = 0; i < rates.length; i++) 983 | total += rates[i]; 984 | 985 | txtRock.setText("" + (100.0 - total)); 986 | } catch (NumberFormatException nfe) { 987 | 988 | } 989 | } 990 | } 991 | } 992 | 993 | class TextFileView extends FileFilter { 994 | 995 | public boolean accept(File f) { 996 | if (f.isDirectory()) { 997 | return true; 998 | } 999 | 1000 | String extension = getExtension(f); 1001 | if (extension != null) 1002 | if (extension.equals("txt")) 1003 | return true; 1004 | 1005 | return false; 1006 | } 1007 | 1008 | private String getExtension(File f) { 1009 | String ext = null; 1010 | String s = f.getName(); 1011 | int i = s.lastIndexOf('.'); 1012 | 1013 | if (i > 0 && i < s.length() - 1) { 1014 | ext = s.substring(i+1).toLowerCase(); 1015 | } 1016 | return ext; 1017 | } 1018 | 1019 | @Override 1020 | public String getDescription() { 1021 | return "Action Files (.txt)"; 1022 | } 1023 | } 1024 | } 1025 | -------------------------------------------------------------------------------- /src/net/buddat/wgenerator/ui/MapPanel.java: -------------------------------------------------------------------------------- 1 | package net.buddat.wgenerator.ui; 2 | 3 | import java.awt.Color; 4 | import java.awt.Graphics; 5 | import java.awt.event.ComponentAdapter; 6 | import java.awt.event.ComponentEvent; 7 | import java.awt.event.MouseAdapter; 8 | import java.awt.event.MouseEvent; 9 | import java.awt.event.MouseMotionAdapter; 10 | import java.awt.event.MouseWheelEvent; 11 | import java.awt.image.BufferedImage; 12 | 13 | import javax.swing.JPanel; 14 | 15 | public class MapPanel extends JPanel { 16 | 17 | private static final long serialVersionUID = -6072723167611034006L; 18 | 19 | private BufferedImage mapImage; 20 | 21 | private int mapSize; 22 | private double scale = 0.0f; 23 | private double minScale = 1.0f; 24 | private int imageX = 0; 25 | private int imageY = 0; 26 | private int startX = 0; 27 | private int startY = 0; 28 | 29 | public MapPanel(int width, int height) { 30 | super(); 31 | 32 | this.setSize(width, height); 33 | this.setMapSize(1024); 34 | 35 | addMouseWheelListener(new MouseAdapter() { 36 | 37 | @Override 38 | public void mouseWheelMoved(MouseWheelEvent e) { 39 | double delta = 0.05f * e.getPreciseWheelRotation(); 40 | if(e.isShiftDown()) 41 | delta *= 2; 42 | int preH = getImageHeight(); 43 | int preW = getImageWidth(); 44 | scale -= delta; 45 | if(scale <= minScale) 46 | scale = minScale; 47 | int offY = (int)((getImageHeight() - preH) / 2); 48 | int offX = (int)((getImageWidth() - preW) / 2); 49 | imageX -= offX; 50 | imageY -= offY; 51 | checkBounds(); 52 | revalidate(); 53 | repaint(); 54 | } 55 | 56 | }); 57 | 58 | this.addComponentListener(new ComponentAdapter() { 59 | public void componentResized(ComponentEvent e) { 60 | updateScale(); 61 | checkBounds(); 62 | } 63 | }); 64 | 65 | this.addMouseListener(new MouseAdapter() { 66 | @Override 67 | public void mousePressed(MouseEvent e) { 68 | super.mousePressed(e); 69 | startX = e.getX(); 70 | startY = e.getY(); 71 | } 72 | }); 73 | 74 | this.addMouseMotionListener(new MouseMotionAdapter() { 75 | @Override 76 | public void mouseDragged(MouseEvent e) { 77 | if(e.getX() < startX) 78 | imageX -= (startX - e.getX()); 79 | else if(e.getX() > startX) 80 | imageX += (e.getX() - startX); 81 | if(e.getY() < startY) 82 | imageY -= (startY - e.getY()); 83 | else if(e.getY() > startY) 84 | imageY += (e.getY() - startY); 85 | startX = e.getX(); 86 | startY = e.getY(); 87 | checkBounds(); 88 | repaint(); 89 | } 90 | }); 91 | 92 | } 93 | 94 | public void updateScale() { 95 | if(this.getWidth() < this.getHeight()) 96 | this.minScale = (double)this.getWidth() / (double)mapImage.getWidth(); 97 | if(this.getHeight() < this.getWidth()) 98 | this.minScale = (double)this.getHeight() / (double)mapImage.getHeight(); 99 | if(this.scale < this.minScale) 100 | this.scale = this.minScale; 101 | } 102 | 103 | private int getImageWidth() { 104 | return (int)Math.round(this.mapImage.getWidth() * this.scale); 105 | } 106 | 107 | private int getImageHeight() { 108 | return (int)Math.round(this.mapImage.getHeight() * this.scale); 109 | } 110 | 111 | public void checkBounds() { 112 | int wH = this.getHeight(); 113 | int wW = this.getWidth(); 114 | int iH = this.getImageHeight(); 115 | int iW = this.getImageWidth(); 116 | int minY = wH - iH; 117 | int minX = wW - iW; 118 | 119 | if(wW > iW) 120 | imageX = (wW / 2) - (iW / 2); 121 | else if(imageX < minX) 122 | imageX = minX; 123 | else if(imageX > 0) 124 | imageX = 0; 125 | 126 | if(wH > iH) 127 | imageY = (wH / 2) - (iH / 2); 128 | else if(imageY < minY) 129 | imageY = minY; 130 | else if(imageY > 0) 131 | imageY = 0; 132 | } 133 | 134 | @Override 135 | public void paintComponent(Graphics g) { 136 | g.setColor(Color.BLACK); 137 | g.fillRect(0, 0, this.getWidth(), this.getHeight()); 138 | g.drawImage(this.mapImage, imageX, imageY, getImageWidth(), getImageHeight(), null); 139 | } 140 | 141 | public void setMapSize(int newMapSize) { 142 | mapSize = newMapSize; 143 | 144 | mapImage = new BufferedImage(mapSize, mapSize, BufferedImage.TYPE_BYTE_GRAY); 145 | updateScale(); 146 | checkBounds(); 147 | scale = minScale; 148 | } 149 | 150 | public void setMapImage(BufferedImage newImage) { 151 | mapImage = newImage; 152 | updateScale(); 153 | checkBounds(); 154 | scale = minScale; 155 | } 156 | 157 | public BufferedImage getMapImage() { 158 | return mapImage; 159 | } 160 | 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/net/buddat/wgenerator/util/Constants.java: -------------------------------------------------------------------------------- 1 | package net.buddat.wgenerator.util; 2 | 3 | /** 4 | * @author Budda 5 | * 6 | * Class containing all default settings for a new map generation. 7 | */ 8 | public class Constants { 9 | 10 | public static final String WINDOW_TITLE = "WGenerator - Map Generator for Wurm Unlimited"; 11 | public static final int WINDOW_SIZE = 768; 12 | 13 | public static final int MAP_SIZE = 2048; 14 | public static final float MAP_HEIGHT = 4096f; 15 | 16 | public static final float SINGLE_DIRT = 1.0f / MAP_HEIGHT; 17 | 18 | public static final double RESOLUTION = MAP_SIZE / 4; 19 | 20 | public static final int HEIGHTMAP_ITERATIONS = 10; 21 | 22 | public static final int MIN_SLOPE = 40; 23 | public static final int MAX_SEDIMENT = 40; 24 | public static final float SEDIMENT_BASE = 0.15f, MAX_SLOPE = 0.9f; 25 | 26 | public static final int DIRT_DROP_COUNT = 60; 27 | public static final int MAX_DIRT_SLOPE = 40; 28 | public static final int MAX_DIRT_DIAG_SLOPE = 56; 29 | public static final int WATER_HEIGHT = 500; 30 | 31 | public static final int EROSION_ITERATIONS = 25; 32 | public static final int ROCK_WEIGHT = 3800; 33 | 34 | public static final int GRASS_ITERATIONS = 50; 35 | public static final int BIOME_RATE = 60; 36 | public static final int BIOME_MAX_SLOPE = 20; 37 | public static final int BIOME_SEEDS = 50; 38 | public static final int BIOME_SIZE = 60; 39 | public static final int BIOME_MIN_HEIGHT = WATER_HEIGHT; 40 | public static final int BIOME_MAX_HEIGHT = ROCK_WEIGHT; 41 | 42 | public static final double ORE_ROCK = 98.9, ORE_IRON = 0.5, ORE_GOLD = 0.025, ORE_SILVER = 0.05, ORE_ZINC = 0.075, 43 | ORE_COPPER = 0.1, ORE_LEAD = 0.1, ORE_TIN = 0.1, ORE_ADDY = 0.0, ORE_GLIMMER = 0.0, ORE_MARBLE = 0.05, ORE_SLATE = 0.1; 44 | 45 | public static final float NORMAL_LOW = 0.5f; 46 | public static final float NORMAL_HIGH = 1.0f - NORMAL_LOW; 47 | 48 | public static final int MIN_EDGE = 64; 49 | public static final double BORDER_WEIGHT = 4.0; 50 | public static final boolean MORE_LAND = false; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/net/buddat/wgenerator/util/SimplexNoise.java: -------------------------------------------------------------------------------- 1 | package net.buddat.wgenerator.util; 2 | 3 | import java.util.Random; 4 | 5 | public class SimplexNoise { 6 | 7 | private static int grad3[][] = { {1,1,0},{-1,1,0},{1,-1,0},{-1,-1,0}, 8 | {1,0,1},{-1,0,1},{1,0,-1},{-1,0,-1}, 9 | {0,1,1},{0,-1,1},{0,1,-1},{0,-1,-1}}; 10 | 11 | private static int p[] = { 151,160,137,91,90,15, 12 | 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 13 | 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 14 | 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 15 | 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 16 | 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 17 | 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 18 | 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 19 | 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 20 | 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 21 | 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 22 | 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 23 | 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180}; 24 | 25 | // To remove the need for index wrapping, double the permutation table length 26 | private static int perm[] = new int[512]; 27 | static { 28 | for(int i = 0; i < 512; i++) 29 | perm[i] = p[i & 255]; 30 | } 31 | 32 | // This method is a *lot* faster than using (int)Math.floor(x) 33 | private static int fastfloor(double x) { 34 | return x > 0 ? (int)x : (int)x - 1; 35 | } 36 | 37 | private static double dot(int g[], double x, double y) { 38 | return g[0] * x + g[1] * y; 39 | } 40 | 41 | // 2D simplex noise 42 | public static double noise(double xin, double yin) { 43 | double n0, n1, n2; 44 | 45 | final double F2 = 0.5 * (Math.sqrt(3.0) - 1.0); 46 | double s = (xin + yin) * F2; 47 | int i = fastfloor(xin + s); 48 | int j = fastfloor(yin + s); 49 | 50 | final double G2 = (3.0 - Math.sqrt(3.0)) / 6.0; 51 | double t = (i + j) * G2; 52 | double X0 = i - t; 53 | double Y0 = j - t; 54 | double x0 = xin - X0; 55 | double y0 = yin - Y0; 56 | 57 | int i1, j1; 58 | if (x0 > y0) { 59 | i1=1; 60 | j1=0; 61 | } else { 62 | i1 = 0; 63 | j1 = 1; 64 | } 65 | 66 | double x1 = x0 - i1 + G2; 67 | double y1 = y0 - j1 + G2; 68 | double x2 = x0 - 1.0 + 2.0 * G2; 69 | double y2 = y0 - 1.0 + 2.0 * G2; 70 | 71 | int ii = i & 255; 72 | int jj = j & 255; 73 | int gi0 = perm[ii + perm[jj]] % 12; 74 | int gi1 = perm[ii + i1 + perm[jj + j1]] % 12; 75 | int gi2 = perm[ii + 1 + perm[jj + 1]] % 12; 76 | 77 | double t0 = 0.5 - x0 * x0 - y0 * y0; 78 | if(t0 < 0) 79 | n0 = 0.0; 80 | else { 81 | t0 *= t0; 82 | n0 = t0 * t0 * dot(grad3[gi0], x0, y0); 83 | } 84 | 85 | double t1 = 0.5 - x1 * x1 - y1 * y1; 86 | if(t1 < 0) 87 | n1 = 0.0; 88 | else { 89 | t1 *= t1; 90 | n1 = t1 * t1 * dot(grad3[gi1], x1, y1); 91 | } 92 | 93 | double t2 = 0.5 - x2 * x2 - y2 * y2; 94 | if(t2 < 0) 95 | n2 = 0.0; 96 | else { 97 | t2 *= t2; 98 | n2 = t2 * t2 * dot(grad3[gi2], x2, y2); 99 | } 100 | 101 | return 70.0 * (n0 + n1 + n2); 102 | } 103 | 104 | public static void genGrad(long seed) { 105 | Random rnd = new Random(seed); 106 | for(int i = 0; i < 255; i++) 107 | p[i] = i; 108 | for(int i = 0; i < 255; i++) { 109 | int j = rnd.nextInt(255); 110 | int nSwap = p[i]; 111 | p[i] = p[j]; 112 | p[j] = nSwap; 113 | } 114 | 115 | for(int i = 0; i < 512; i++) 116 | perm[i] = p[i & 255]; 117 | } 118 | 119 | } --------------------------------------------------------------------------------