/******************************************************************************* * Copyright (c) 2015 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *******************************************************************************/ package jsettlers.graphics.test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Timer; import java.util.TimerTask; import jsettlers.common.CommonConstants; import jsettlers.common.buildings.EBuildingType; import jsettlers.common.buildings.IBuilding; import jsettlers.common.landscape.ELandscapeType; import jsettlers.common.map.EDebugColorModes; import jsettlers.common.map.IGraphicsBackgroundListener; import jsettlers.common.map.IGraphicsGrid; import jsettlers.common.map.partition.IPartitionData; import jsettlers.common.map.shapes.MapCircle; import jsettlers.common.map.shapes.MapShapeFilter; import jsettlers.common.mapobject.IMapObject; import jsettlers.common.material.EMaterialType; import jsettlers.common.movable.EDirection; import jsettlers.common.movable.EMovableType; import jsettlers.common.movable.IMovable; import jsettlers.common.position.ShortPoint2D; public class TestMap implements IGraphicsGrid { private static final int HEIGHT = 150; private static final int WIDTH = 150; private static final int SETTLERS = 300; private static final int BUILDINGS = 80; private static final double HEIGHTCIRCLESIZE = 40; private static final int RIVERS = 50; private static final int MATERIALS = 100; private static final int TREES = 50; private static final int TREES_IN_FOREST = 40; private static final int FORESTS = 30; private static final double FORESTSIZE = 20; private static final int STONES_IN_GROUP = 10; private static final int STONEGROUPS = 15; private ArrayList<TestTile> tiles = new ArrayList<TestTile>(); private ArrayList<TestSettler> settlers = new ArrayList<TestSettler>(); private ArrayList<TestBuilding> buildings = new ArrayList<TestBuilding>(); // only for direction, ... calculations, not for displaying. // MapDrawContext context = new MapDrawContext(this); private byte[][] heights = new byte[WIDTH][HEIGHT]; public TestMap() { generateHeights(); for (int i = 0; i < WIDTH * HEIGHT; i++) { int x = i % WIDTH; int y = i / WIDTH; TestTile tile = new TestTile((short) x, (short) y, this.heights[x][y]); this.tiles.add(tile); } addRivers(); addSettlers(); addBuildings(); addMaterials(); addTrees(); // addPlayers(); addStones(); Timer timer = new Timer(true); timer.schedule(new TimerTask() { @Override public void run() { moveStep(); } }, 100, 100); } private void addTrees() { for (int i = 0; i < TREES; i++) { int cx = (int) (Math.random() * WIDTH); int cy = (int) (Math.random() * HEIGHT); TestTile tile = getTile(cx, cy); if (tile.getLandscapeType() == ELandscapeType.GRASS) { tile.setMapObject(new TestTree()); } } for (int i = 0; i < FORESTS; i++) { int cx = (int) (Math.random() * (WIDTH - FORESTSIZE)); int cy = (int) (Math.random() * (HEIGHT - FORESTSIZE)); addForrest(cx, cy); } } private void addForrest(int x, int y) { for (int i = 0; i < TREES_IN_FOREST; i++) { int cx = (int) (Math.random() * FORESTSIZE) + x; int cy = (int) (Math.random() * FORESTSIZE) + y; TestTile tile = getTile(cx, cy); if (tile.getLandscapeType() == ELandscapeType.GRASS) { tile.setMapObject(new TestTree()); } } } private void addStones() { for (int j = 0; j < STONEGROUPS; j++) { int x = (int) (Math.random() * (WIDTH - FORESTS)); int y = (int) (Math.random() * (HEIGHT - FORESTSIZE)); for (int i = 0; i < STONES_IN_GROUP; i++) { int cx = (int) (Math.random() * FORESTSIZE) + x; int cy = (int) (Math.random() * FORESTSIZE) + y; TestTile tile = getTile(cx, cy); if (tile.getLandscapeType() == ELandscapeType.GRASS) { tile.setMapObject(new TestStone((int) (Math.random() * 14))); } } } } private TestTile getTile(int x, int y) { int i = y * WIDTH + x; if (i < tiles.size() && i >= 0) { return this.tiles.get(i); } else { return null; } } public TestTile getTile(ShortPoint2D pos) { return getTile(pos.x, pos.y); } private void addBuildings() { for (int i = 0; i < BUILDINGS; i++) { int cx = (int) (Math.random() * WIDTH); int cy = (int) (Math.random() * HEIGHT); TestTile tile = getTile(cx, cy); TestBuilding building = null; if (tile.getLandscapeType() == ELandscapeType.GRASS) { building = new TestBuilding(tile.getPos(), EBuildingType.LUMBERJACK); } else if (tile.getLandscapeType() == ELandscapeType.MOUNTAIN) { building = new TestBuilding(tile.getPos(), EBuildingType.COALMINE); } else if (tile.getLandscapeType() == ELandscapeType.SAND) { building = new TestBuilding(tile.getPos(), EBuildingType.FISHER); } if (building != null) { this.buildings.add(building); tile.setBuilding(building); } } } private void addSettlers() { for (int i = 0; i < SETTLERS; i++) { int cx = (int) (Math.random() * WIDTH); int cy = (int) (Math.random() * HEIGHT); if (this.heights[cx][cy] < 3 || this.heights[cx][cy] > 10) { continue; } TestTile tile = getTile(cx, cy); EMovableType type = getRandomSettlerType(); TestSettler settler = new TestSettler(getRandomDirection(), type, tile, (byte) (Math.random() * 8)); if (type == EMovableType.BEARER) { settler.setMaterial(getRandomMaterial()); } tile.setMovable(settler); this.settlers.add(settler); } } private EMovableType getRandomSettlerType() { if (Math.random() < .6) { return EMovableType.BEARER; } else { return EMovableType.values()[(int) (Math.random() * EMovableType.NUMBER_OF_MOVABLETYPES)]; } } private EDirection getRandomDirection() { int random = (int) (Math.random() * 6); switch (random) { case 0: return EDirection.EAST; case 1: return EDirection.NORTH_EAST; case 2: return EDirection.NORTH_WEST; case 3: return EDirection.WEST; case 4: return EDirection.SOUTH_WEST; default: return EDirection.SOUTH_EAST; } } private EMaterialType getRandomMaterial() { int random = (int) (Math.random() * 23); switch (random) { case 0: return EMaterialType.AXE; case 1: return EMaterialType.BOW; case 2: return EMaterialType.BREAD; case 3: return EMaterialType.COAL; case 4: return EMaterialType.CROP; case 5: return EMaterialType.FISH; case 6: return EMaterialType.FISHINGROD; case 7: return EMaterialType.FLOUR; case 8: return EMaterialType.GOLD; case 9: return EMaterialType.GOLDORE; case 10: return EMaterialType.HAMMER; case 11: return EMaterialType.IRON; case 12: return EMaterialType.IRONORE; case 13: return EMaterialType.MEAT; case 14: return EMaterialType.NO_MATERIAL; case 15: return EMaterialType.PICK; case 16: return EMaterialType.PIG; case 17: return EMaterialType.PLANK; case 18: return EMaterialType.SAW; case 19: return EMaterialType.SCYTHE; case 20: return EMaterialType.SPEAR; case 21: return EMaterialType.SWORD; case 22: return EMaterialType.WATER; default: return EMaterialType.TRUNK; } } private void generateHeights() { for (int x = 0; x < WIDTH; x++) { for (int y = 0; y < HEIGHT; y++) { this.heights[x][y] = (byte) (-3 * Math.random()); } } for (int i = 0; i < 30; i++) { int cx = (int) (Math.random() * WIDTH); int cy = (int) (Math.random() * HEIGHT); double r = Math.random() * HEIGHTCIRCLESIZE; MapCircle circle = new MapCircle((short) cx, (short) cy, (float) r); for (ShortPoint2D pos : new MapShapeFilter(circle, WIDTH, HEIGHT)) { double add = (r - circle.distanceToCenter(pos.x, pos.y)) / 5; this.heights[pos.x][pos.y] += (byte) add; } } for (int x = 0; x < WIDTH; x++) { for (int y = 0; y < HEIGHT; y++) { if (this.heights[x][y] < 0) { this.heights[x][y] = 0; } } } smootHeights(); removeCanyons(); } private void removeCanyons() { for (int y = 0; y < HEIGHT - 2; y++) { for (int x = 0; x < WIDTH - 2; x++) { if (this.heights[x + 1][y] < this.heights[x][y] && this.heights[x + 1][y] < this.heights[x + 2][y]) { this.heights[x + 1][y] = this.heights[x][y]; } if (this.heights[x][y + 1] < this.heights[x][y] && this.heights[x][y + 1] < this.heights[x][y + 2]) { this.heights[x][y + 1] = this.heights[x][y]; } } } } private int smootHeights() { int changed = 0; for (int y = 0; y < HEIGHT - 1; y++) { for (int x = 0; x < WIDTH - 1; x++) { if (this.heights[x + 1][y] > this.heights[x][y] + 1) { this.heights[x + 1][y] = (byte) (this.heights[x][y] + 1); changed++; } else if (this.heights[x + 1][y] < this.heights[x][y] - 1) { this.heights[x + 1][y] = (byte) (this.heights[x][y] - 1); changed++; } if (this.heights[x][y + 1] > this.heights[x][y] + 1) { this.heights[x][y + 1] = (byte) (this.heights[x][y] + 1); changed++; } else if (this.heights[x][y + 1] < this.heights[x][y] - 1) { this.heights[x][y + 1] = (byte) (this.heights[x][y] - 1); changed++; } } } return changed; } private void addRivers() { for (int i = 0; i < RIVERS; i++) { int x = (int) (Math.random() * WIDTH); int y = (int) (Math.random() * HEIGHT); TestTile current = getTile(x, y); if (current.getLandscapeType() != ELandscapeType.GRASS) { continue; } while (current != null && !current.getLandscapeType().isWater()) { current.setRiver(true); List<EDirection> directions = Arrays.asList(EDirection.VALUES); Collections.shuffle(directions); TestTile goTo = null; for (EDirection possibleDirection : directions) { TestTile tile = this.getTile(possibleDirection.getNextHexPoint(current.getPos())); if (tile != null && tile.getHeight() <= current.getHeight() && tile.getLandscapeType() != ELandscapeType.RIVER1 && tile.getLandscapeType() != ELandscapeType.RIVER2 && tile.getLandscapeType() != ELandscapeType.RIVER3 && tile.getLandscapeType() != ELandscapeType.RIVER4 && getNeighbourRiverCount(tile) < 2) { goTo = tile; break; } } current = goTo; } } } private int getNeighbourRiverCount(TestTile tile) { int rivers = 0; for (EDirection dir : EDirection.VALUES) { TestTile toTest = this.getTile(dir.getNextHexPoint(tile.getPos())); if (toTest != null && (toTest.getLandscapeType() == ELandscapeType.RIVER1 || toTest.getLandscapeType() == ELandscapeType.RIVER2 || toTest.getLandscapeType() == ELandscapeType.RIVER3 || toTest.getLandscapeType() == ELandscapeType.RIVER4)) { rivers++; } } return rivers; } private void addMaterials() { for (int i = 0; i < MATERIALS; i++) { int x = (int) (Math.random() * WIDTH); int y = (int) (Math.random() * HEIGHT); EMaterialType type = getRandomMaterial(); int count = (int) (Math.random() * 8 + 1); TestTile tile = getTile(x, y); ELandscapeType landscape = tile.getLandscapeType(); if (allowsStackPlacement(landscape)) { tile.setStack(new TestStack(type, count)); } } } private static boolean allowsStackPlacement(ELandscapeType landscape) { return landscape.isWater() && landscape != ELandscapeType.MOOR && landscape != ELandscapeType.RIVER1 && landscape != ELandscapeType.RIVER2 && landscape != ELandscapeType.RIVER3 && landscape != ELandscapeType.RIVER4 && landscape != ELandscapeType.SNOW; } public void moveStep() { for (TestSettler settler : this.settlers) { settler.increaseProgress(); if (settler.moveOn()) { TestTile newPosition = this.getTile(settler.getDirection().getNextHexPoint(settler.getPos())); if (newPosition == null) { // should not happen EDirection direction = getRandomDirection(); settler.setDirection(direction); } else { TestTile nextPosition = this.getTile(settler.getDirection().getNextHexPoint(newPosition.getPos())); this.getTile(settler.getPos()).setMovable(null); newPosition.setMovable(settler); settler.setPosition(newPosition); if (nextPosition == null || nextPosition.getMovable() != null || nextPosition.getLandscapeType() == ELandscapeType.WATER1) { // may not move... EDirection direction = getRandomDirection(); settler.setDirection(direction); } } } } for (TestBuilding bulding : this.buildings) { bulding.increaseConstructed(); } } public EBuildingType getConstructionPreviewBuilding() { return null; } @Override public short getHeight() { return HEIGHT; } @Override public short getWidth() { return WIDTH; } public TestTile getTile(short x, short y) { return getTile((int) x, (int) y); } /** * Gets any unspecified building. * * @return The building. */ public IBuilding getAnyBuilding() { return this.buildings.get(0); } public List<? extends IMovable> getAllSettlers() { return this.settlers; } @Override public IMovable getMovableAt(int x, int y) { return getTile(x, y).getMovable(); } @Override public IMapObject getMapObjectsAt(int x, int y) { if (getTile(x, y).getBuilding() != null) { return getTile(x, y).getBuilding(); } else { return getTile(x, y).getHeadMapObject(); } } @Override public byte getHeightAt(int x, int y) { return getTile(x, y).getHeight(); } @Override public ELandscapeType getLandscapeTypeAt(int x, int y) { return getTile(x, y).getLandscapeType(); } @Override public int getDebugColorAt(int x, int y, EDebugColorModes debugColorMode) { return -1; } @Override public boolean isBorder(int x, int y) { return false; } @Override public byte getPlayerIdAt(int x, int y) { return 0; } @Override public byte getVisibleStatus(int x, int y) { return CommonConstants.FOG_OF_WAR_VISIBLE; } @Override public void setBackgroundListener(IGraphicsBackgroundListener backgroundListener) { } @Override public int nextDrawableX(int x, int y, int maxX) { return x + 1; } @Override public IPartitionData getPartitionData(int x, int y) { return null; } @Override public boolean isBuilding(int x, int y) { return false; } }