package com.weem.epicinventor.world; import com.weem.epicinventor.*; import com.weem.epicinventor.world.block.*; import java.util.Random; import java.util.ArrayList; import java.awt.*; import com.weem.epicinventor.utility.*; public class WorldCavern { World world; private static int MAX_CAVES = 3; private static int MIN_CAVES = 2; private static int numberCaves = 0; private static int CAVERN_FACTOR; private static int CAVE_RADIUS; private static float CAVE_TERM; private static int[] gound; private BlockManager blockManager; private WorldTown worldTown; private static Random randGen = new Random(); public WorldCavern(World w, WorldTown wt, int cavernFactor, int caveRadius, float caveTerm, int[] worldGround) { blockManager = new BlockManager(); worldTown = wt; world = w; gound = worldGround; CAVERN_FACTOR = cavernFactor; CAVE_RADIUS = caveRadius; CAVE_TERM = caveTerm; } public int[][] carveCavern(int[][] currentBlockArray, int size, int xMin, int xMax, int zMin, int zMax, int paintRadius, float splitPercentage) { int x = randGen.nextInt(xMax - xMin) + xMin; int z = randGen.nextInt(zMax - zMin) + zMin; numberCaves = 2; int cave_x1 = 0; int cave_z1 = 0; int cave_x2 = 0; int cave_z2 = 0; int currentPaintRadius = paintRadius; int angle = 0; int distance = 0; int[] worldSize = world.getWorldSize(); cave_x1 = (int) (x + (currentPaintRadius - (CAVE_RADIUS + 1)) * Math.sin(30 * Math.PI / 180)); cave_z1 = (int) (z - (currentPaintRadius - (CAVE_RADIUS + 1)) * Math.cos(30 * Math.PI / 180)); for (int i = 0; i < CAVERN_FACTOR; i++) { world.PaintAtPoint(currentBlockArray, "CaveBG", currentPaintRadius, x, z, (x / size) * size, size); if (i == CAVERN_FACTOR - 1) { cave_x2 = (int) (x - (currentPaintRadius - (CAVE_RADIUS + 1)) * Math.sin(30 * Math.PI / 180)); cave_z2 = (int) (z - (currentPaintRadius - (CAVE_RADIUS + 1)) * Math.cos(30 * Math.PI / 180)); } x += randGen.nextInt(Math.max(currentPaintRadius / 2, 1)) - currentPaintRadius / 2; z += randGen.nextInt(Math.max(currentPaintRadius / 4, 1)) - currentPaintRadius / 8; currentPaintRadius = randGen.nextInt(paintRadius / 2) + paintRadius / 2; } angle = randGen.nextInt(25 - 15) + 15; distance = randGen.nextInt(40 - 30) + 30; int cave_x1_end = (int) (cave_x1 + distance * Math.cos(angle * Math.PI / 180)); int cave_z1_end = (int) (cave_z1 + distance * Math.sin(angle * Math.PI / 180)); currentBlockArray = world.PaintLine(currentBlockArray, "CaveBG", CAVE_RADIUS, cave_x1, cave_z1, cave_x1_end, cave_z1_end, 0, 0, worldSize[0], worldSize[1]); angle = randGen.nextInt(25 - 15) + 15; distance = randGen.nextInt(30 - 20) + 20; int cave_x2_end = (int) (cave_x2 - distance * Math.cos(angle * Math.PI / 180)); int cave_z2_end = (int) (cave_z2 + distance * Math.sin(angle * Math.PI / 180)); currentBlockArray = world.PaintLine(currentBlockArray, "CaveBG", CAVE_RADIUS, cave_x2, cave_z2, cave_x2_end, cave_z2_end, 0, 0, worldSize[0], worldSize[1]); currentBlockArray = carveCave(currentBlockArray, cave_x1_end, cave_z1_end, 0, 0, worldSize[0], worldSize[1], 0.02f, World.direction.Right); currentBlockArray = carveCave(currentBlockArray, cave_x2_end, cave_z2_end, 0, 0, worldSize[0], worldSize[1], 0.02f, World.direction.Left); // Add cave. Game.loadingText = "Digging Caves"; EIError.debugMsg("Add cave noise", EIError.ErrorLevel.Notice); float[][] caveNoise; for (int b = 0; b < world.HORIZ_BLOCKS; b++) { caveNoise = world.GeneratePerlinNoise(32); caveNoise = world.InterpolateData(caveNoise, 32, size); for (int i = 0; i < 60; i++) { world.PaintWithRandomWalk(currentBlockArray, caveNoise, size, Rand.getRange(5, size / 64), "CaveBG", false, b * size, (b + 1) * size - 1, world.GROUND_LEVEL / 8, world.GROUND_LEVEL, size / 2); } } for(int i = 0; i < 20; i++) { drawCrag(currentBlockArray, "CaveBG", Rand.getRange(5, 10), Rand.getRange(0, worldSize[0]), Rand.getRange(size / 8, worldSize[1]), 0, worldSize[0], 0, 3 * worldSize[1] / 4); } return currentBlockArray; } public int[][] carveCave(int[][] currentBlockArray, int startX, int startZ, int minX, int minZ, int maxX, int maxZ, float splitPercentage, World.direction lastDirection) { boolean split = false; int angleMin = 0; int angleMax = 25; int distanceMin = 5; int distanceMax = 15; int angle = 0; int distance = 0; World.direction direction = lastDirection; World.direction splitDirection = lastDirection; int endX = 0; int endZ = 0; float chance = 0.0f; int[] groundLoc; int[] newEnd; do { angle = randGen.nextInt(angleMax - angleMin) + angleMin; distance = randGen.nextInt(distanceMax - distanceMin) + distanceMin; direction = getDirection(lastDirection); if (direction == World.direction.Right) { endX = (int) (startX + distance * Math.cos(angle * Math.PI / 180)); } else { endX = (int) (startX - distance * Math.cos(angle * Math.PI / 180)); } //near x bounds change direction if (endX + CAVE_RADIUS > maxX) { endX = (int) (startX - distance * Math.cos(angle * Math.PI / 180)); direction = World.direction.Left; lastDirection = World.direction.Left; } if (endX - CAVE_RADIUS < minX) { endX = (int) (startX + distance * Math.cos(angle * Math.PI / 180)); direction = World.direction.Right; lastDirection = World.direction.Right; } endZ = (int) (startZ + distance * Math.sin(angle * Math.PI / 180)); groundLoc = willBreakGround(startX, startZ, endX, endZ); //near ground if (groundLoc[3] == 1) { newEnd = avoidTown(worldTown, startX, startZ, endX, endZ, maxX); if (newEnd[0] > 0 && newEnd[1] > 0) { endX = newEnd[0]; endZ = newEnd[1]; if (direction == World.direction.Left) { direction = World.direction.Right; lastDirection = World.direction.Right; } else { direction = World.direction.Left; lastDirection = World.direction.Left; } groundLoc = willBreakGround(startX, startZ, endX, endZ); if (groundLoc[0] > 0 && groundLoc[1] > 0) { endX = groundLoc[0]; endZ = groundLoc[1]; } } //stop at ground } else if (groundLoc[0] > 0 && groundLoc[1] > 0) { endX = groundLoc[0]; endZ = groundLoc[1]; } currentBlockArray = world.PaintLine(currentBlockArray, "CaveBG", CAVE_RADIUS + Rand.getRange(0, 2), startX, startZ, endX, endZ, minX, minZ, maxX, maxZ); chance = randGen.nextFloat(); if (chance <= (splitPercentage * CAVE_TERM) && numberCaves > MIN_CAVES) { break; } if (chance <= splitPercentage && numberCaves < MAX_CAVES) { if (direction == World.direction.Left) { splitDirection = World.direction.Right; } else { splitDirection = World.direction.Left; } currentBlockArray = carveCave(currentBlockArray, endX, endZ, minX, minZ, maxX, maxZ, splitPercentage, direction); currentBlockArray = carveCave(currentBlockArray, endX, endZ, minX, minZ, maxX, maxZ, splitPercentage, splitDirection); numberCaves++; split = true; } startX = endX; startZ = endZ; } while (split == false && groundLoc[0] == 0 && groundLoc[1] == 0 && groundLoc[2] == 0); return currentBlockArray; } private void drawCrag(int[][] currentBlockArray, String group, int paintRadius, int x, int z, int minX, int maxX, int minZ, int maxZ) { if(x > minX && x < maxX) { if(gound[x] <= z + paintRadius + 10) { z -= paintRadius * 2; } if(gound[x] > z + paintRadius + 10) { world.PaintAtPoint(currentBlockArray, group, paintRadius, x, z, minX, maxX, minZ, maxZ); int spines = Rand.getRange(4, 10); int direction = 0; for(int i = 0; i < spines; i++) { direction = Rand.getRange(360 * i / spines, 360 * i / spines + (360 / spines)); drawSpine(currentBlockArray, group, paintRadius / 2, direction, x, z, minX, maxX, minZ, maxZ); } } } } private void drawSpine(int[][] currentBlockArray, String group, int paintRadius, int currentDirection, int x, int z, int minX, int maxX, int minZ, int maxZ) { if(x > minX && x < maxX && z > minZ && z < maxZ) { if(paintRadius != 0 && gound[x] > z + paintRadius + 10) { int directionOffset = Rand.getRange(-20, 20); int paintRadiusChange = -1 * Rand.getRange(0, 1); int newX = x + (int)(paintRadius * Math.cos(Math.toRadians(currentDirection + directionOffset))); int newZ = z + (int)(paintRadius * Math.sin(Math.toRadians(currentDirection + directionOffset))); world.PaintAtPoint(currentBlockArray, group, paintRadius + paintRadiusChange, newX, newZ, minX, maxX, minZ, maxZ); if(paintRadius > 0) { drawSpine(currentBlockArray, group, paintRadius + paintRadiusChange, currentDirection + directionOffset, newX, newZ, minX, maxX, minZ, maxZ); } } } return; } private int[] avoidTown(WorldTown wt, int startX, int startZ, int endX, int endZ, int maxX) { int[] newEnd = new int[2]; newEnd[0] = 0; newEnd[1] = 0; ArrayList townAreas = wt.getTownAreas(); int size = townAreas.size(); World.direction direction = World.direction.Left; if (size > 0) { int[] townBounds = (int[]) townAreas.get(0); int townSize = townBounds[1] - townBounds[0]; if (startX > endX) { if (endX <= 2 * townSize) { direction = World.direction.Right; } else { for (int i = 0; i < size; i++) { townBounds = (int[]) townAreas.get(i); if (townBounds[1] >= endX - 30 && townBounds[1] <= endX) { direction = World.direction.Right; break; } } } } else { direction = World.direction.Right; if (endX >= maxX - 2 * townSize) { direction = World.direction.Left; } else { for (int i = 0; i < size; i++) { townBounds = (int[]) townAreas.get(i); if (townBounds[0] <= endX + 30 && townBounds[0] >= endX) { direction = World.direction.Left; break; } } } } if ((startX > endX && direction == World.direction.Right) || (startX < endX && direction == World.direction.Left)) { newEnd[0] = 2 * startX - endX; newEnd[1] = startZ; //System.out.println(newEnd[0]+","+newEnd[1]+" "+endX+","+endZ); } } return newEnd; } private World.direction getDirection(World.direction lastDirection) { World.direction direction = lastDirection; float chance = randGen.nextFloat(); if (chance < 0.02f) { if (lastDirection == World.direction.Left) { direction = World.direction.Right; } else { direction = World.direction.Left; } } return direction; } public int[] willBreakGround(int startX, int startZ, int endX, int endZ) { int[] groundLoc = new int[4]; groundLoc[0] = 0; groundLoc[1] = 0; groundLoc[2] = 0; groundLoc[3] = 0; int dx = endX - startX; int dz = endZ - startZ; int count = (int) Math.sqrt(dx * dx + dz * dz); int i; double angle = 0.0; for (i = 0; i < count; i++) { if (gound[startX + (dx * i / count)] - (40 + CAVE_RADIUS) <= startZ + (dz * i / count)) { groundLoc[3] = 1; } if (gound[startX + (dx * i / count)] + CAVE_RADIUS * 2 / 3 <= startZ + (dz * i / count)) { groundLoc[2] = 1; break; } } if (groundLoc[2] == 1) { if (i < 2) { i = 2; } angle = Math.atan((gound[startX + (dx * i / count)] + CAVE_RADIUS * 2 - startZ) / (dx * i / count)) * 180 / Math.PI; if (angle < 46.0) { endZ = gound[startX + (dx * i / count)] + CAVE_RADIUS * 2; endX = dx * i / count + startX; groundLoc[2] = 0; } else { endZ -= dz / 3 + startZ; } dx = endX - startX; dz = endZ - startZ; } for (i = 0; i < count; i++) { if (gound[startX + (dx * i / count)] + CAVE_RADIUS <= startZ + (dz * i / count)) { groundLoc[0] = startX + (dx * i / count); groundLoc[1] = startZ + (dz * i / count); break; } } return groundLoc; } }