package greymerk.roguelike.dungeon; import java.util.ArrayList; import java.util.List; import java.util.Random; import greymerk.roguelike.config.RogueConfig; import greymerk.roguelike.dungeon.base.IDungeonRoom; import greymerk.roguelike.util.graph.Edge; import greymerk.roguelike.util.graph.Graph; import greymerk.roguelike.util.mst.MinimumSpanningTree; import greymerk.roguelike.worldgen.Cardinal; import greymerk.roguelike.worldgen.Coord; import greymerk.roguelike.worldgen.IWorldEditor; public class LevelGeneratorMST implements ILevelGenerator{ IWorldEditor editor; Random rand; IDungeonLevel level; private DungeonNode end; private List<DungeonNode> nodes; private List<DungeonTunnel> tunnels; public LevelGeneratorMST(IWorldEditor editor, Random rand, IDungeonLevel level){ this.editor = editor; this.rand = rand; this.level = level; nodes = new ArrayList<DungeonNode>(); tunnels = new ArrayList<DungeonTunnel>(); } @Override public void generate(Coord start, DungeonNode oldEnd) { MinimumSpanningTree mst = new MinimumSpanningTree(rand, 7, 17, new Coord(start)); Graph<Coord> layout = mst.getGraph(); List<Edge<Coord>> edges = layout.getEdges(); List<Coord> vertices = layout.getPoints(); List<Edge<Coord>> used = new ArrayList<Edge<Coord>>(); for(Coord c : vertices){ for(Edge<Coord> e : edges){ if(used.contains(e)) continue; Coord[] ends = new Coord[]{e.getStart(), e.getEnd()}; for(Coord p : ends){ if(p.equals(c)){ Cardinal dir = getDirection(ends, p); Coord tStart = ends[0]; Coord tEnd = ends[1]; this.tunnels.add(new DungeonTunnel(editor, tStart, tEnd, dir)); used.add(e); } } } } DungeonNode startDungeonNode = null; for(Coord c : vertices){ List<Cardinal> entrances = new ArrayList<Cardinal>(); for(DungeonTunnel tunnel : this.tunnels){ Coord[] ends = tunnel.getEnds(); if(ends[0].equals(c)){ entrances.add(tunnel.getDirection()); } else if(ends[1].equals(c)) { entrances.add(Cardinal.reverse(tunnel.getDirection())); } } Cardinal[] ents = new Cardinal[entrances.size()]; DungeonNode toAdd = new DungeonNode(entrances.toArray(ents), c); this.nodes.add(toAdd); if(c.equals(start)){ startDungeonNode = toAdd; } } int attempts = 0; do{ end = this.nodes.get(rand.nextInt(this.nodes.size())); attempts++; } while(end == startDungeonNode || end.getPosition().distance(start) > (16 + attempts * 2)); // assign dungeons for (DungeonNode node : nodes){ if(node == end || node == startDungeonNode) continue; // TODO: Find way to check available space when picking room IDungeonRoom toGenerate = this.level.getSettings().getRooms().get(rand); node.setDungeon(toGenerate); } if(RogueConfig.getBoolean(RogueConfig.ENCASE)){ for (DungeonNode node : nodes){ if(node == end || node == startDungeonNode) continue; node.encase(editor, rand, this.level.getSettings().getTheme()); } for(DungeonTunnel t : this.getTunnels()){ t.encase(editor, rand, this.level.getSettings().getTheme()); } } for(DungeonTunnel t : this.getTunnels()){ t.construct(editor, rand, this.level.getSettings()); } for (DungeonNode node : nodes){ if(node == end || node == startDungeonNode) continue; IDungeonRoom toGenerate = node.getRoom(); toGenerate.generate(editor, rand, this.level.getSettings(), node.getEntrances(), node.getPosition()); } for(DungeonTunnel tunnel : this.getTunnels()){ tunnel.genSegments(editor, rand, this.level); } LevelGenerator.generateLevelLink(editor, rand, this.level.getSettings(), start, oldEnd); } public DungeonNode getEnd(){ return this.end; } private Cardinal getDirection(Coord[] ends, Coord p){ Coord c1; Coord c2; if(p.equals(ends[0])){ c1 = ends[0]; c2 = ends[1]; } else { c1 = ends[1]; c2 = ends[0]; } if(c2.getX() - c1.getX() == 0){ if(c2.getZ() - c1.getZ() < 0){ return Cardinal.NORTH; } else { return Cardinal.SOUTH; } } else { if(c2.getX() - c1.getX() < 0){ return Cardinal.WEST; } else { return Cardinal.EAST; } } } @Override public List<DungeonNode> getNodes() { return this.nodes; } @Override public List<DungeonTunnel> getTunnels() { return this.tunnels; } }