package com.bioxx.jmapgen.processing;
import java.util.Vector;
import net.minecraft.util.math.BlockPos;
import com.bioxx.jmapgen.IslandMap;
import com.bioxx.jmapgen.IslandParameters.Feature;
import com.bioxx.jmapgen.attributes.Attribute;
import com.bioxx.jmapgen.attributes.OreAttribute;
import com.bioxx.jmapgen.graph.Center;
import com.bioxx.jmapgen.graph.Center.HexDirection;
import com.bioxx.jmapgen.graph.Center.Marker;
import com.bioxx.tfc2.api.Global;
import com.bioxx.tfc2.api.ore.OreConfig;
import com.bioxx.tfc2.api.ore.OreConfig.VeinType;
import com.bioxx.tfc2.api.ore.OreRegistry;
public class OreProcessor
{
IslandMap map;
public OreProcessor(IslandMap m)
{
map = m;
}
public void generate()
{
OreConfig[] configs = OreRegistry.getInstance().getConfigsForStone(map.getParams().getSurfaceRock());
Vector<Center> landCenters = map.getCentersAbove(0.02);
if(landCenters.size() == 0)
return;
for(OreConfig oc : configs)
{
int total = Math.max(map.getParams().hasFeature(Feature.MineralRich) ? oc.getRarity()/2 : 1, 1);
total = map.mapRandom.nextInt(map.getParams().hasFeature(Feature.MineralRich) ? oc.getRarity() * 2 : oc.getRarity()) + total;
for(int i = 0; i < total; i++)
{
if(oc.getVeinType() == VeinType.Seam)
genSeam(landCenters.get(map.mapRandom.nextInt(landCenters.size())), oc);
else if(oc.getVeinType() == VeinType.Layer)
genLayer(landCenters.get(map.mapRandom.nextInt(landCenters.size())), oc);
}
}
}
private void genLayer(Center start, OreConfig oc)
{
/**
* Stage 0: Setup all of our variables
*/
int maxLength = oc.getMinSeamLength()+map.mapRandom.nextInt(oc.getMaxSeamLength()-oc.getMinSeamLength());
int curLength = 0;
HexDirection seamDir = HexDirection.values()[map.mapRandom.nextInt(HexDirection.values().length)];
Center prevCenter = null;
Center center = start;
Center nextCenter = start.getNeighbor(seamDir);
Center sCenter, sNextCenter;
OreAttrNode sCurNode, sNextNode;
OreAttrNode curNode = new OreAttrNode(oc.getOreName());
int startElev = (int)(mcElev(start.getElevation())*0.75);
startElev = map.mapRandom.nextInt(Math.max(startElev, 10));
curNode.setOffset(new BlockPos(center.point.x, startElev, center.point.y));
setupHeightAndWidth(oc, curNode);
OreAttrNode nextNode = new OreAttrNode(oc.getOreName());
nextNode.setOffset(new BlockPos(nextCenter.point.x, curNode.getOffset().getY(), nextCenter.point.y));
int elevOffset = 0;
double nextDir = 0.5;
while(curLength < maxLength)
{
/**
* Stage 1: Cycle the data to start the next iteration
*/
//Link our current and next nodes together
curNode.setNext(nextCenter);
nextNode.setPrev(center);
//apply the node data to the current center
addNode(center, curNode);
//Elevation validation
if(nextNode.offset.getY() > mcElev(nextCenter.getElevation()))
{
int diff = nextNode.offset.getY() - mcElev(nextCenter.getElevation());
nextNode.offset = nextNode.offset.add(0, (-diff) - 10, 0);
}
else if(nextNode.offset.getY() < (int)(mcElev(nextCenter.getElevation()) * 0.2))
{
int diff = (int)(mcElev(nextCenter.getElevation()) * 0.2) - nextNode.offset.getY();
nextNode.offset = nextNode.offset.add(0, diff+2 , 0);
}
if(nextCenter.hasAnyMarkersOf(Marker.Border))
{
curLength = maxLength;
continue;
}
//Otherwise we continue
curNode = nextNode;
prevCenter = center;
center = nextCenter;
//Finished cycling
/**
* Stage 2: Setup up our nodes with relevant data
*/
setupHeightAndWidth(oc, curNode);
//first we perform the bias math
elevOffset = (int)Math.floor((double)oc.getNoiseVertical() * 2.0d);
//then we apply the bias to the vertical noise
elevOffset = oc.getNoiseVertical() - map.mapRandom.nextInt(elevOffset);
nextCenter = center.getNeighbor(seamDir.getRandomTurnBig(map.mapRandom));
//Sanity
if(nextCenter == null)
nextCenter = center.getRandomNeighbor(map.mapRandom);
//Create our next node
nextNode = new OreAttrNode(oc.getOreName());
nextNode.setOffset(new BlockPos(nextCenter.point.x, curNode.getOffset().getY() + elevOffset, nextCenter.point.y));
curLength++;
}
}
private void genSeam(Center start, OreConfig oc)
{
/**
* Stage 0: Setup all of our variables
*/
int maxLength = oc.getMinSeamLength()+map.mapRandom.nextInt(oc.getMaxSeamLength()-oc.getMinSeamLength());
int curLength = 0;
HexDirection seamDir = HexDirection.values()[map.mapRandom.nextInt(HexDirection.values().length)];
Center prevCenter = null;
Center center = start;
Center nextCenter = start.getNeighbor(seamDir);
Center sCenter, sNextCenter;
OreAttrNode sCurNode, sNextNode;
OreAttrNode curNode = new OreAttrNode(oc.getOreName());
int startElev = (int)(mcElev(start.getElevation())*0.75);
startElev = map.mapRandom.nextInt(Math.max(startElev, 10));
curNode.setOffset(new BlockPos(center.point.x, startElev, center.point.y));
setupHeightAndWidth(oc, curNode);
OreAttrNode nextNode = new OreAttrNode(oc.getOreName());
nextNode.setOffset(new BlockPos(nextCenter.point.x, curNode.getOffset().getY(), nextCenter.point.y));
nextNode.setPrevOffset(getMidpoint(curNode.getOffset(), nextNode.getOffset()));
curNode.setNextOffset(nextNode.getPrevOffset());
int elevOffset = 0;
double nextDir = 0.5;
while(curLength < maxLength)
{
/**
* Stage 1: Cycle the data to start the next iteration
*/
//Link our current and next nodes together
curNode.setNext(nextCenter);
nextNode.setPrev(center);
//apply the node data to the current center
addNode(center, curNode);
//Elevation validation
if(nextNode.offset.getY() > mcElev(nextCenter.getElevation()))
{
int diff = nextNode.offset.getY() - mcElev(nextCenter.getElevation());
nextNode.offset = nextNode.offset.add(0, (-diff) - 10, 0);
}
else if(nextNode.offset.getY() < (int)(mcElev(nextCenter.getElevation()) * 0.2))
{
int diff = (int)(mcElev(nextCenter.getElevation()) * 0.2) - nextNode.offset.getY();
nextNode.offset = nextNode.offset.add(0, diff+2 , 0);
}
if(nextCenter.hasAnyMarkersOf(Marker.Border))
{
curLength = maxLength;
continue;
}
//Otherwise we continue
curNode = nextNode;
prevCenter = center;
center = nextCenter;
//Finished cycling
/**
* Stage 2: Setup up our nodes with relevant data
*/
setupHeightAndWidth(oc, curNode);
//Create little offshoots of the main seam.
if(oc.getSubSeamRarity() > 0 && map.mapRandom.nextInt(oc.getSubSeamRarity()) == 0)
{
int subSeamLength = map.mapRandom.nextInt(2)+1;
HexDirection subSeamDir = seamDir.getRandomTurnBig(map.mapRandom, false);
//Perform initial setup
sCenter = center;
sCurNode = new OreAttrNode(oc.getOreName());
sCurNode.setOffset(curNode.getOffset());
sCurNode.setNodeHeight(Math.max(curNode.getNodeHeight()/2, 1));
sCurNode.setNodeWidth(Math.max(curNode.getNodeWidth()/2, 1));
sNextNode = new OreAttrNode(oc.getOreName());
sNextCenter = sCenter.getNeighbor(subSeamDir);
sCurNode.setNext(sNextCenter);
if(sNextCenter == null)
break;
elevOffset = oc.getNoiseVertical()*2 - map.mapRandom.nextInt(oc.getNoiseVertical() * 4);
sNextNode.setOffset(new BlockPos(sNextCenter.point.x, sCurNode.getOffset().getY() + elevOffset, sNextCenter.point.y));
sCurNode.setNextOffset(getMidpoint(sCurNode.getOffset(), sNextNode.getOffset()));
sNextNode.setPrevOffset(sCurNode.getNextOffset());
sNextNode.setPrev(sCenter);
addNode(sCenter, sCurNode);
while(subSeamLength > 0)
{
// Begin Cycling
sCurNode = sNextNode;
sCenter = sNextCenter;
// End Cycling
if(oc.getNoiseVertical() >= 10 && map.mapRandom.nextDouble() < 0.15)
{
sNextCenter = sCenter;
elevOffset = oc.getNoiseVertical() - map.mapRandom.nextInt((int)Math.floor(oc.getNoiseVertical() * 2));
}
else
{
sNextCenter = sCenter.getNeighbor(subSeamDir.getRandomTurnSmall(map.mapRandom));
elevOffset = oc.getNoiseVertical() - map.mapRandom.nextInt((int)Math.floor(oc.getNoiseVertical() * 2));
}
if(sNextCenter == null)
break;
sCurNode.setNodeHeight(Math.max(curNode.getNodeHeight()/2, 1));
sCurNode.setNodeWidth(Math.max(curNode.getNodeWidth()/2, 1));
sNextNode = new OreAttrNode(oc.getOreName());
sNextNode.setOffset(new BlockPos(sNextCenter.point.x, sCurNode.getOffset().getY() + elevOffset, sNextCenter.point.y));
//Elevation validation
if(sNextNode.offset.getY() > mcElev(sNextCenter.getElevation()))
{
int diff = sNextNode.offset.getY() - mcElev(sNextCenter.getElevation());
sNextNode.offset = sNextNode.offset.add(0, (-diff) - 10, 0);
}
else if(sNextNode.offset.getY() < (int)(mcElev(sNextCenter.getElevation()) * 0.2))
{
int diff = (int)(mcElev(sNextCenter.getElevation()) * 0.2) - sNextNode.offset.getY();
sNextNode.offset = sNextNode.offset.add(0, diff+2 , 0);
}
//Link the current node and the next node together
sCurNode.setNext(sNextCenter);
sCurNode.setNextOffset(getMidpoint(sCurNode.getOffset(), sNextNode.getOffset()).add(
oc.getNoiseHorizontal()-map.mapRandom.nextInt((oc.getNoiseHorizontal()*2)),
elevOffset,
oc.getNoiseHorizontal()-map.mapRandom.nextInt((oc.getNoiseHorizontal()*2))));
sNextNode.setPrevOffset(sCurNode.getNextOffset());
sNextNode.setPrev(sCenter);
addNode(sCenter, sCurNode);
subSeamLength--;
}
}
//first we perform the bias math
elevOffset = (int)Math.floor((double)oc.getNoiseVertical() * 2.0d);
//then we apply the bias to the vertical noise
elevOffset = oc.getNoiseVertical() - map.mapRandom.nextInt(elevOffset);
nextCenter = center.getNeighbor(seamDir.getRandomTurnSmall(map.mapRandom));
if(map.mapRandom.nextDouble() < 0.05) //Otherwise, 5% chance that a seam will spike vertically within the same hex
{
nextCenter = center;
elevOffset *= 2;
}
//Sanity
if(nextCenter == null)
nextCenter = center.getRandomNeighbor(map.mapRandom);
//Create our next node
nextNode = new OreAttrNode(oc.getOreName());
nextNode.setOffset(new BlockPos(nextCenter.point.x, curNode.getOffset().getY() + elevOffset, nextCenter.point.y));
int horiz = oc.getNoiseHorizontal()*2;
//Setup the midpoint offsets for each node
nextNode.setPrevOffset(getMidpoint(curNode.getOffset(), nextNode.getOffset()).add(oc.getNoiseHorizontal()-map.mapRandom.nextInt(horiz), 0, oc.getNoiseHorizontal()-map.mapRandom.nextInt(horiz)));
curNode.setNextOffset(nextNode.getPrevOffset());
curLength++;
}
}
private void setupHeightAndWidth(OreConfig oc, OreAttrNode curNode) {
if(oc.getVeinHeightMin() == oc.getVeinHeightMax())
curNode.setNodeHeight(oc.getVeinHeightMin());
else
curNode.setNodeHeight(oc.getVeinHeightMin()+map.mapRandom.nextInt(oc.getVeinHeightMax()-oc.getVeinHeightMin()));
if(oc.getVeinWidthMin() == oc.getVeinWidthMax())
curNode.setNodeWidth(oc.getVeinWidthMin());
else
curNode.setNodeWidth(oc.getVeinWidthMin()+map.mapRandom.nextInt(oc.getVeinWidthMax()-oc.getVeinWidthMin()));
}
private BlockPos getMidpoint(BlockPos p0, BlockPos p1)
{
int x = (p0.getX() + p1.getX()) / 2;
int y = (p0.getY() + p1.getY()) / 2;
int z = (p0.getZ() + p1.getZ()) / 2;
return new BlockPos(x, y, z);
}
private void addNode(Center c, OreAttrNode n)
{
OreAttribute attrib = (OreAttribute) c.getAttribute(Attribute.Ore);
if(attrib == null)
{
attrib = new OreAttribute();
c.addAttribute(attrib);
}
attrib.addNode(n);
}
private Center getHighestNonRiverNeighbor(Center c)
{
Center out = null;
for(Center n : c.neighbors)
{
if(n.hasAttribute(Attribute.River))
continue;
if(out == null || n.getElevation() > out.getElevation())
out = n;
}
return out;
}
private int mcElev(double d)
{
return map.convertHeightToMC(d)+Global.SEALEVEL;
}
private Vector<Center> getCentersBetween(Vector<Center> centers, double min, double max)
{
Vector<Center> out = new Vector<Center>();
for(Center c : centers)
{
if (c.elevation > min && c.getElevation() < max)
out.add(c);
}
return out;
}
private Vector<Center> getBeachesWithCliffs(Vector<Center> centers)
{
Vector<Center> out = new Vector<Center>();
for(Center c : centers)
{
if(!c.hasMarker(Marker.Coast))
continue;
Center n = c.getHighestNeighbor();
if(mcElev(n.getElevation()) - mcElev(c.getElevation()) < 8)
continue;
out.add(c);
}
return out;
}
private Vector<Center> getCoastalOcean(Vector<Center> centers)
{
Vector<Center> out = new Vector<Center>();
for(Center c : centers)
{
if(!c.hasMarker(Marker.CoastWater))
continue;
Center n = c.getLowestNeighbor();
if(mcElev(c.getElevation()) - mcElev(n.getElevation()) < 8)
continue;
out.add(n);
}
return out;
}
}