Basic world generation for entire Vault dimension

This commit is contained in:
simon 2018-02-26 17:17:40 -05:00
parent 817dbcc6c4
commit f530dafdee

View File

@ -4,7 +4,11 @@ import net.simon987.server.GameServer;
import net.simon987.server.game.Direction;
import net.simon987.server.game.World;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Random;
public class VaultDimension {
@ -17,18 +21,153 @@ public class VaultDimension {
name = "v" + vaultDoorId + "-";
/*
* Creates a group of vault worlds and pieces them together with openings.
* For a set number of passes, a random number of vault worlds are added to each world in the
* previous 'layer' of worlds in a random direction. Openings are added to allow movement from a
* layer to the next, meaning that adjacent worlds are not necessarily connected, and one would
* necessarily need to travel through 5 openings to reach the 6th layer, even when that layer is
* less than 5 worlds away from the origin/home vault world (the one containing the exit door).
*
* 1. Create home world (layer 0)
* 2. For each world in the current layer, attach a random number of new worlds
* 3. Repeat the same step for the newly added layer
* 4. Choose a random world from the last layer and create the vault box there (objective)
*
* This process is actually done in 2 passes, in the first pass, worlds are defined
* as a set of coordinates + a list of opening directions, then they are actually generated
*/
int minLayerCount = 4;
int maxLayerCount = 6;
int minAttachedWorld = 0;
int maxAttachedWorld = 4; //todo cap at 4 to avoid infinite loop
HashMap<Integer, ArrayList<WorldBluePrint>> worldLayers = new HashMap<>();
VaultWorldGenerator generator = new VaultWorldGenerator();
Random random = new Random();
int layerCount = random.nextInt(maxLayerCount - minLayerCount) + minLayerCount;
ArrayList<Direction> openings = new ArrayList<>();
openings.add(Direction.WEST);
openings.add(Direction.SOUTH);
openings.add(Direction.EAST);
openings.add(Direction.NORTH);
//1. Create home world
WorldBluePrint homeWorld = new WorldBluePrint();
homeWorld.coords.x = 0x7FFF;
homeWorld.coords.y = 0x7FFF;
worldLayers.put(0, new ArrayList<>());
worldLayers.get(0).add(homeWorld);
World vWorld = generator.generateVaultWorld(0x7FFF, 0x7FFF, openings, name);
//2. For each world in the current layer, attach a random number of new worlds
for (int i = 1; i <= layerCount; i++) {
GameServer.INSTANCE.getGameUniverse().addWorld(vWorld);
worldLayers.put(i, new ArrayList<>());
for (WorldBluePrint world : worldLayers.get(i - 1)) {
int attachedWorlds;
if (i == 1) {
attachedWorlds = 4; // The home world should have 4 attached worlds
} else {
attachedWorlds = random.nextInt(maxAttachedWorld - minAttachedWorld) + minAttachedWorld;
}
for (int j = 0; j < attachedWorlds; j++) {
int rDirIndex = random.nextInt(4);
//Try 4 directions (wrap around 0..3)
for (int attemptCount = 0; attemptCount < 4; attemptCount++) {
Direction rDir = Direction.getDirection(rDirIndex);
//Don't attach a world at the same spot twice
if (!worldExists(world.coordinatesOf(rDir), worldLayers)) {
WorldBluePrint attachedWorld = world.attachWorld(rDir);
worldLayers.get(i).add(attachedWorld);
}
rDirIndex = (rDirIndex + 1) % 4;
}
}
}
}
ArrayList<World> lastLayerWorlds = new ArrayList<>();
//Generate worlds
for (Integer key : worldLayers.keySet()) {
ArrayList<WorldBluePrint> layer = worldLayers.get(key);
for (WorldBluePrint bp : layer) {
World vWorld = generator.generateVaultWorld(bp.coords.x, bp.coords.y, bp.openings, name);
GameServer.INSTANCE.getGameUniverse().addWorld(vWorld);
if (key == layerCount - 1) {
lastLayerWorlds.add(vWorld);
}
}
}
//4. Choose a random world from the last layer and create the vault box there (objective)
World objectiveWorld = lastLayerWorlds.get(random.nextInt(lastLayerWorlds.size()));
}
private boolean worldExists(Point coords, HashMap<Integer, ArrayList<WorldBluePrint>> worldLayers) {
//Auto-generated by IntelliJ Idea
return worldLayers.values().stream().flatMap(Collection::stream).anyMatch(bp -> bp.coords.equals(coords));
}
private class WorldBluePrint {
public ArrayList<Direction> openings = new ArrayList<>(4);
public Point coords = new Point();
/**
* Update the blueprint's openings to allow traveling to the newly attached world
*
* @param direction direction of the world to attach (relative to this one)
* @return The blueprint of the attached world
*/
public WorldBluePrint attachWorld(Direction direction) {
WorldBluePrint attachedWorld = new WorldBluePrint();
switch (direction) {
case NORTH:
openings.add(Direction.NORTH);
attachedWorld.openings.add(Direction.SOUTH);
break;
case EAST:
openings.add(Direction.EAST);
attachedWorld.openings.add(Direction.WEST);
break;
case SOUTH:
openings.add(Direction.SOUTH);
attachedWorld.openings.add(Direction.NORTH);
break;
case WEST:
openings.add(Direction.WEST);
attachedWorld.openings.add(Direction.EAST);
break;
}
attachedWorld.coords.x = coords.x + direction.dX;
attachedWorld.coords.y = coords.y + direction.dY;
return attachedWorld;
}
/**
* Get the coordinates of a world that would be attached to this world
*
* @param direction direction of the attached world
*/
Point coordinatesOf(Direction direction) {
return new Point(coords.x + direction.dX, coords.y + direction.dY);
}
}
}