package com.bioxx.tfc2.handlers; import java.util.*; import net.minecraft.init.Blocks; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import com.bioxx.jmapgen.IslandMap; import com.bioxx.jmapgen.Point; import com.bioxx.jmapgen.attributes.Attribute; import com.bioxx.jmapgen.dungeon.*; import com.bioxx.jmapgen.dungeon.RoomSchematic.RoomType; import com.bioxx.jmapgen.graph.Center; import com.bioxx.tfc2.Core; import com.bioxx.tfc2.TFC; import com.bioxx.tfc2.TFCBlocks; import com.bioxx.tfc2.api.events.IslandGenEvent; import com.bioxx.tfc2.api.types.WoodType; import com.bioxx.tfc2.blocks.BlockStoneBrick; import com.bioxx.tfc2.blocks.BlockStoneSmooth; public class CreateDungeonHandler { private boolean[] tempMap; @SubscribeEvent public void createDungeon(IslandGenEvent.Post event) { DungeonSchemManager dsm = DungeonSchemManager.getInstance(); Random random = event.islandMap.mapRandom; Vector<Center> dungeonCenters = event.islandMap.getLandCenters(); dungeonCenters = this.removeRiverCenters(dungeonCenters); dungeonCenters = event.islandMap.getCentersAbove(dungeonCenters, 0.3); dungeonCenters = event.islandMap.getCentersBelow(dungeonCenters, 0.6, false); if(dungeonCenters.size() == 0) return; //Find a suitable location for the entrance Center start = null; int counter = 0; while(start == null) { start = dungeonCenters.get(random.nextInt(dungeonCenters.size())); //pick a relatively flat area. if(counter > 2500 || Math.abs(start.getAverageElevation() - start.getElevation()) <= 0.08) { break; } start = null; counter++; } //We want our dungeon to have its entrance in this chunk. int xStartChunk = ((int)(start.point.x) >> 4); int zStartChunk = ((int)(start.point.y) >> 4); //Elevation of the center int startElev = event.islandMap.convertHeightToMC(start.getElevation())+64; //this is the Y level where the dungeon will start int elev = startElev-30; DungeonTheme dungeonTheme = dsm.getRandomTheme(random); Dungeon dungeon = new Dungeon(dungeonTheme.getThemeName(), xStartChunk, elev, zStartChunk); dungeon.blockMap.put("dungeon_wall", TFCBlocks.StoneBrick.getDefaultState().withProperty(BlockStoneBrick.META_PROPERTY, event.islandMap.getParams().getSurfaceRock())); dungeon.blockMap.put("dungeon_floor", Core.getPlanks(WoodType.getTypeFromString(event.islandMap.getParams().getCommonTree()))); dungeon.blockMap.put("dungeon_ceiling", TFCBlocks.StoneBrick.getDefaultState().withProperty(BlockStoneBrick.META_PROPERTY, event.islandMap.getParams().getSurfaceRock())); dungeon.blockMap.put("dungeon_smoothstone", TFCBlocks.StoneSmooth.getDefaultState().withProperty(BlockStoneSmooth.META_PROPERTY, event.islandMap.getParams().getSurfaceRock())); dungeon.blockMap.put("dungeon_stairs_floor", TFCBlocks.StairsOak.getDefaultState()); dungeon.blockMap.put("dungeon_stairs_wall", TFCBlocks.StairsOak.getDefaultState()); dungeon.blockMap.put("dungeon_door", Blocks.OAK_DOOR.getDefaultState()); while(true) { genDungeon(event.islandMap, dungeonTheme, random, xStartChunk, zStartChunk, dungeon); if(dungeon.getRoomCount() > 30) break; dungeon.resetDungeonMap(); } TFC.log.info("Dungeon: " + start.point.toString() + " | Size : " + dungeon.getRoomCount()); event.islandMap.dungeons.add(dungeon); } private void genDungeon(IslandMap map, DungeonTheme dungeonTheme, Random random, int xStartChunk, int zStartChunk, Dungeon dungeon) { DungeonRoom dungeonEntrance = new DungeonRoom(dungeonTheme.getRandomEntrance(random), dungeon.dungeonStart); dungeon.setRoom(xStartChunk, 0, zStartChunk, dungeonEntrance); LinkedList<DungeonRoom> queue = new LinkedList<DungeonRoom>(); queue.add(dungeonEntrance); while(queue.peek() != null) { DungeonRoom room = queue.poll(); boolean isRoomValid = true; boolean addedRoom = false; for(DungeonDirection dir : room.getSchematic().getConnections()) { RoomPos pos = room.getPosition().offset(dir); //Have we already established a connection in this direction? if(isRoomValid && !room.hasConnection(dir)) { DungeonRoom neighbor = dungeon.getRoom(room.getPosition().offset(dir)); /** * Create a new random room in this direction */ if(neighbor == null && checkElevation(map, dungeon, room.getPosition().offset(dir))) { RoomSchematic schem = null; double dist = room.getPosition().offset(dir).distanceSq(dungeon.dungeonStart); if(dist > 256) schem = dungeonTheme.getRandomRoomSingleDirection(random, dir.getOpposite()); else if(random.nextDouble() < 0.25 && room.getPosition().getY() > 16) schem = dungeonTheme.getRandomRoomForDirection(random, dir.getOpposite(), RoomType.Stairs); else schem = dungeonTheme.getRandomRoomForDirection(random, dir.getOpposite()); if(schem == null) continue; neighbor = new DungeonRoom(schem, room.getPosition().offset(dir)); linkRooms(room, neighbor, dir); addedRoom = true; if(!neighbor.getSchematic().getSetPieceMap().isEmpty()) { if(checkSetPiece(map, dungeon, neighbor.getPosition(), neighbor.getSchematic().getSetPieceMap())) { Iterator<RoomPos> iter = neighbor.getSchematic().getSetPieceMap().keySet().iterator(); while(iter.hasNext()) { RoomPos setPos = iter.next(); String s = neighbor.getSchematic().getSetPieceMap().get(setPos); setPos = pos.add(setPos); DungeonRoom setpieceRoom = new DungeonRoom(dungeonTheme.getSchematic(s), setPos); dungeon.setRoom(setPos, setpieceRoom); queue.add(setpieceRoom); } } else { neighbor.clearConnections(dungeon); neighbor = null; } } } else if(neighbor != null)//A room already exists in this neighbor location { //If the neighbor can connect to this room then link them if(neighbor.getSchematic().getConnections().contains(dir.getOpposite())) { linkRooms(room, neighbor, dir); } } if(neighbor != null && addedRoom) { queue.add(neighbor); dungeon.setRoom(neighbor); } } if(!isRoomValid) break; } if(!isRoomValid) { room.clearConnections(dungeon); requeueNeighbors(queue, dungeon, room); dungeon.setRoom(room.getPosition(), null); } } } boolean checkElevation(IslandMap map, Dungeon dungeon, RoomPos pos) { Center closest = map.getClosestCenter(new Point((pos.getX() << 4)+8, (pos.getZ() << 4)+8)); if(pos.getY()+14 > map.convertHeightToMC(closest.getElevation())+64)//we do 14 instead of 10 to make sure that the schematic is a bit deeper underground return false; if(pos.getY() > dungeon.dungeonStart.getY()) return false; return true; } boolean checkSetPiece(IslandMap islandMap, Dungeon dungeon, RoomPos startPos, Map<RoomPos, String> map) { Iterator<RoomPos> iter = map.keySet().iterator(); while(iter.hasNext()) { RoomPos pos = iter.next(); RoomPos pos2 = startPos.add(pos); if(dungeon.getRoom(pos2) != null) return false; if(!checkElevation(islandMap, dungeon, pos2)) return false; } return true; } void requeueNeighbors(LinkedList<DungeonRoom> queue, Dungeon dungeon, DungeonRoom room) { DungeonRoom other = dungeon.getRoom(room.getPosition().offset(DungeonDirection.NORTH)); if(other != null) queue.add(other); other = dungeon.getRoom(room.getPosition().offset(DungeonDirection.SOUTH)); if(other != null) queue.add(other); other = dungeon.getRoom(room.getPosition().offset(DungeonDirection.EAST)); if(other != null) queue.add(other); other = dungeon.getRoom(room.getPosition().offset(DungeonDirection.WEST)); if(other != null) queue.add(other); other = dungeon.getRoom(room.getPosition().offset(DungeonDirection.UP)); if(other != null) queue.add(other); other = dungeon.getRoom(room.getPosition().offset(DungeonDirection.DOWN)); if(other != null) queue.add(other); } void linkRooms(DungeonRoom room1, DungeonRoom room2, DungeonDirection room1_dir) { room1.addConnection(room1_dir, new RoomLink(true)); room2.addConnection(room1_dir.getOpposite(), new RoomLink(false)); } public Vector<Center> removeRiverCenters(Vector<Center> list) { Vector<Center> out = new Vector<Center>(); for(Center c : list) { if(!c.hasAttribute(Attribute.River)) out.add(c); } return out; } }