public BuildingSubworldBuilder(Building building, BuildingVoxels vox, BuildingGenerationPlan plan) { Building = building; BuildVox = vox; Plan = plan; Size = new Vec2i(building.Width, building.Height); int cWidth = Mathf.CeilToInt(((float)Size.x) / World.ChunkSize); int cHeight = Mathf.CeilToInt(((float)Size.z) / World.ChunkSize); if (cWidth < 1) { cWidth = 1; } if (cHeight < 1) { cHeight = 1; } ChunkSize = new Vec2i(cWidth, cHeight); Tiles = new int[cWidth, cHeight][, ]; Voxels = new ChunkVoxelData[cWidth, cHeight]; Objects = new List <WorldObjectData> [cWidth, cHeight]; for (int x = 0; x < cWidth; x++) { for (int z = 0; z < cHeight; z++) { Tiles[x, z] = new int[World.ChunkSize, World.ChunkSize]; Voxels[x, z] = new ChunkVoxelData(); } } }
/// <summary> /// Attempts to place generate a building based on <paramref name="bp"/> in the plot specified /// </summary> /// <param name="bp"></param> /// <param name="plot"></param> private bool GenBuildingInPlot(BuildingPlan bp, Plot plot) { Vec2i entrance = GenerationRandom.RandomFromArray(plot.EntranceSides); BuildingGenerationPlan bpPlan = new BuildingGenerationPlan() { BuildingPlan = bp, EntranceSide = entrance, MaxHeight = plot.Bounds.Height, MaxWidth = plot.Bounds.Width }; if (bp.MinSize > plot.Bounds.Width || bp.MinSize > plot.Bounds.Height) { return(false); } Building b = BuildingGenerator.CreateBuilding(GenerationRandom, out BuildingVoxels vox, bpPlan); Vec2i pos = new Vec2i(plot.Bounds.X, plot.Bounds.Y); if (entrance.x == -1) { pos = new Vec2i(plot.Bounds.X, plot.Bounds.Y + GenerationRandom.RandomIntFromSet(0, plot.Bounds.Height - b.Height)); } else if (entrance.x == 1) { pos = new Vec2i(plot.Bounds.X + (plot.Bounds.Width - b.Width), plot.Bounds.Y + GenerationRandom.RandomIntFromSet(0, plot.Bounds.Height - b.Height)); } else if (entrance.z == -1) { pos = new Vec2i(plot.Bounds.X + GenerationRandom.RandomIntFromSet(0, plot.Bounds.Width - b.Width), plot.Bounds.Y); } else if (entrance.z == 1) { pos = new Vec2i(plot.Bounds.X + GenerationRandom.RandomIntFromSet(0, plot.Bounds.Width - b.Width), plot.Bounds.Y + (plot.Bounds.Height - b.Height)); } Recti r = AddBuilding(b, vox, pos); if (r != null) { BuildingPlots.Add(r); return(true); } return(false); }
public static Farm GenerateVegFarm(GenerationRandom genRan, Farm farm, out BuildingVoxels vox, BuildingGenerationPlan plan) { vox = new BuildingVoxels(farm.Width, World.ChunkHeight, farm.Height); Tile[,] tiles = new Tile[farm.Width, farm.Height]; BuildingGenerator.SetTiles(tiles, 0, 0, farm.Width - 1, farm.Height - 1, Tile.TEST_MAGENTA); farm.SetBuilding(tiles); BuildingGenerator.BuildBoundingWallRect(vox, farm.Width, farm.Height, 2, Voxel.stone); BuildingGenerator.ChooseEntrancePoint(genRan, vox, farm, plan, false); return(farm); }
public static void ChooseEntrancePoint(GenerationRandom genRan, BuildingVoxels vox, Building build, BuildingGenerationPlan plan, bool requiredSubworld = true) { Vec2i entranceSide = plan.EntranceSide; Vec2i mid = new Vec2i(build.Width / 2, build.Height / 2); Vec2i entr = null; //Travel out iterativly till we reach the wall for (int r = 0; r < Mathf.Max(build.Width, build.Height); r++) { Vec2i v = mid + entranceSide * r; if (v.x < 0 || v.z < 0 || v.x >= build.Width || v.z >= build.Height) { break; } if (vox.GetVoxel(v.x, 1, v.z) != Voxel.none) { entr = v; break; } } if (entr == null) { entr = new Vec2i(2, 2); } build.SetEntrancePoint(entr); for (int y = 0; y < 4; y++) { vox.ClearVoxel(entr.x, y, entr.z); } if (requiredSubworld) { Door interior = new Door(); interior.SetRotation(Vector2.Angle(Vector2.up, entranceSide)); interior.SetPosition(entr); build.InternalEntranceObject = interior; AddObject(build, vox, interior, true); Door external = new Door(); external.SetPosition(entr); external.SetRotation(Vector2.Angle(Vector2.up, entranceSide)); build.ExternalEntranceObject = external; build.AddExternalObject(external); } }
public static Building CreateBuilding(GenerationRandom genRan, out BuildingVoxels vox, BuildingGenerationPlan plan) { Vec2i zero = new Vec2i(0, 0); int maxWidth = (plan.DesiredSize == null || plan.DesiredSize == zero) ?Mathf.Min(plan.BuildingPlan.MaxSize, plan.MaxWidth): plan.DesiredSize.x; int maxHeight = (plan.DesiredSize == null || plan.DesiredSize == zero)? Mathf.Min(plan.BuildingPlan.MaxSize, plan.MaxHeight) : plan.DesiredSize.z; int width = genRan.RandomInt(plan.BuildingPlan.MinSize, maxWidth); int height = genRan.RandomInt(plan.BuildingPlan.MinSize, maxHeight); if (plan.BuildingPlan == Building.BLACKSMITH) { Blacksmith smith = BlacksmithGenerator.GenerateBlacksmith(genRan, new Blacksmith(width, height), out vox, plan); return(smith); } if (plan.BuildingPlan == Building.BARACKS) { Barracks barr = BarracksGenerator.GenerateBarracks(genRan, new Barracks(width, height), out vox, plan); return(barr); } if (plan.BuildingPlan == Building.TAVERN) { return(TavernGenerator.GenerateTavern(genRan, new Tavern(width, height), out vox, plan)); } if (plan.BuildingPlan == Building.VEGFARM) { Farm farm = FarmGenerator.GenerateVegFarm(genRan, new Farm(width, height), out vox, plan); return(farm); } if (plan.BuildingPlan == Building.WHEATFARM) { Farm farm = FarmGenerator.GenerateWheatFarm(genRan, new Farm(width, height), out vox, plan); return(farm); } House house = HouseGenerator.GenerateHouse(genRan, new House(width, height), out vox, plan); return(house); //return GenerateHouse(out vox, width, height); }
public static Blacksmith GenerateBlacksmith(GenerationRandom genRan, Blacksmith smith, out BuildingVoxels vox, BuildingGenerationPlan plan) { vox = new BuildingVoxels(smith.Width, World.ChunkHeight, smith.Height); ChooseWallBounds(genRan, smith); BuildingGenerator.ConnectBoundingWall(vox, smith.BoundingWall, Voxel.stone); Tile[,] tileMap = new Tile[smith.Width, smith.Height]; //Make the whole floor stone BuildingGenerator.SetTiles(tileMap, 0, 0, smith.Width - 1, smith.Height - 1, Tile.STONE_FLOOR); Vec2i outSideMin = null; Vec2i outSideMax = null; //Find the outdoor part and make the floor dirt for (int i = 0; i < smith.BoundingWall.Length; i++) { Vec2i p = smith.BoundingWall[i]; //If this boundry point does not lie on any of the edges, then it is indented into the //building. This means this point defines the outside region of the building. if ((p.x != 0 && p.x != smith.Width - 1) && (p.z != 0 && p.z != smith.Height - 1)) { //We get the 2 neigboring wall points, as these define the outside region Vec2i nm1 = smith.BoundingWall[(i - 1 + smith.BoundingWall.Length) % smith.BoundingWall.Length]; Vec2i np1 = smith.BoundingWall[(i + 1) % smith.BoundingWall.Length]; int minX = Mathf.Min(p.x, nm1.x, np1.x); int minZ = Mathf.Min(p.z, nm1.z, np1.z); int maxX = Mathf.Max(p.x, nm1.x, np1.x); int maxZ = Mathf.Max(p.z, nm1.z, np1.z); BuildingGenerator.SetTiles(tileMap, minX, minZ, maxX - minX, maxZ - minZ, Tile.DIRT); outSideMin = new Vec2i(minX, minZ); outSideMax = new Vec2i(maxX, maxZ); break; } } smith.SetBuilding(tileMap); PlaceOutsideObjects(genRan, smith, vox, outSideMin, outSideMax); BuildingGenerator.ChooseEntrancePoint(genRan, vox, smith, plan); BuildingGenerator.AddWindow(genRan, vox, smith); BuildingGenerator.AddWindow(genRan, vox, smith); BuildingGenerator.AddWindow(genRan, vox, smith, autoReattempt: false); BuildingGenerator.AddWindow(genRan, vox, smith, autoReattempt: false); BuildingGenerator.PlaceObjectAgainstWall(genRan, new Chest(), 0, vox, smith, .1f, attemptsCount: 20, distToEntr: 4); BuildingGenerator.PlaceObjectAgainstWall(genRan, new WeaponStand(), 0, vox, smith, 0.1f, distToEntr: 4); BuildingGenerator.PlaceObjectAgainstWall(genRan, new ArmourStand(), 0, vox, smith, .1f, distToEntr: 4); WorkBuildingData wbd = new WorkBuildingData(new NPCJob[] { new NPCJobMerchant(smith), new NPCJobBlackSmith(smith), new NPCJobBlackSmith(smith) }); smith.SetWorkBuildingData(wbd); for (int i = 0; i < 10; i++) { smith.Inventory.AddItem(new Shirt(new ItemMetaData().SetColor(Color.blue))); } return(smith); }
public static Barracks GenerateBarracks(GenerationRandom genRan, Barracks barr, out BuildingVoxels vox, BuildingGenerationPlan plan) { vox = new BuildingVoxels(barr.Width, World.ChunkHeight, barr.Height); ChooseWallBounds(genRan, barr); BuildingGenerator.ConnectBoundingWall(vox, barr.BoundingWall, Voxel.stone); Tile[,] tileMap = new Tile[barr.Width, barr.Height]; BuildingGenerator.ChooseEntrancePoint(genRan, vox, barr, plan); BuildingGenerator.SetTiles(tileMap, 0, 0, barr.Width / 2, barr.Height - 1, Tile.STONE_FLOOR); BuildingGenerator.SetTiles(tileMap, barr.Width / 2, 0, barr.Width / 2 - 1, barr.Height - 1, Tile.DIRT); List <NPCJob> jobs = new List <NPCJob>(); for (int x = 2; x < barr.Height; x += 3) { Vector3 pos = new Vector3(barr.Width - 2, 0, x); float rotation = Vec2i.Angle(Vec2i.Forward, BuildingGenerator.GetWallPointDirection(barr, new Vec2i(barr.Width - 2, x))); TrainingDummy obj = new TrainingDummy().SetPosition(pos).SetRotation(rotation) as TrainingDummy; if (BuildingGenerator.AddObject(barr, vox, obj)) { jobs.Add(new NPCJobSoldier(barr)); } } WorkBuildingData wbd = new WorkBuildingData(jobs.ToArray()); barr.SetWorkBuildingData(wbd); barr.SetBuilding(tileMap); return(barr); }
/// <summary> /// Attempts to place multiple buildings inside this plot /// Works in order. i.e, if we can fit the first, we try to fit the second /// If we can't fit the second, we do no further checks /// If we can, we check the third.. and so on /// We return the number of buildings succesfully placed /// </summary> /// <param name="bps"></param> /// <param name="startIndex">The index of the first building to place</param> /// <param name="plot"></param> /// <returns>The number of buildings placed in this plot, between 0 and 4 (incusive)</returns> private int GenMultipleBuildingsInPlot(List <BuildingPlan> bps, int startIndex, Plot plot) { //Represents 4 points for 4 corners of plot bool[,] isCornerPossible = new bool[2, 2]; bool[] sideHasPath = new bool[4]; //Iterate all entrances foreach (Vec2i v in plot.EntranceSides) { if (v.x == -1) { sideHasPath[0] = true; isCornerPossible[0, 0] = true; isCornerPossible[0, 1] = true; } else if (v.x == 1) { sideHasPath[1] = true; isCornerPossible[1, 0] = true; isCornerPossible[1, 1] = true; } if (v.z == -1) { sideHasPath[2] = true; isCornerPossible[0, 0] = true; isCornerPossible[1, 0] = true; } else if (v.z == 1) { sideHasPath[3] = true; isCornerPossible[0, 1] = true; isCornerPossible[1, 1] = true; } } //Buildings sorted by the corner they have been placed in Recti[,] bounds = new Recti[2, 2]; int j = 0; for (int x = 0; x < 2; x++) { for (int z = 0; z < 2; z++) { //Index of adjacect x, and adjacent z int adjX = (x + 1) % 2; int adjZ = (x + 1) % 2; Recti adjacentX = bounds[adjX, z]; int adjacentXWidth = adjacentX == null ? 0 : adjacentX.Width; Recti adjacentZ = bounds[x, adjZ]; int adjacentZHeight = adjacentZ == null ? 0 : adjacentZ.Height; //check this corner is free if (isCornerPossible[x, z]) { if (startIndex + j >= bps.Count) { return(j); } BuildingPlan plan = bps[startIndex + j]; int maxWidth = plot.Bounds.Width - adjacentXWidth; int maxHeight = plot.Bounds.Height - adjacentZHeight; //If it won't fit, we continue if (maxWidth < plan.MinSize || maxHeight < plan.MinSize) { continue; } int desWidth = GenerationRandom.RandomInt(plan.MinSize, Mathf.Min(plan.MaxSize, maxWidth)); int desHeight = GenerationRandom.RandomInt(plan.MinSize, Mathf.Min(plan.MaxSize, maxHeight)); List <Vec2i> posSides = new List <Vec2i>(); Vec2i entranceSide = null; Vec2i pos = null; //We calculate the entrance side and position of each building if (x == 0 && z == 0) { if (sideHasPath[2]) { posSides.Add(new Vec2i(0, -1)); } if (sideHasPath[0]) { posSides.Add(new Vec2i(-1, 0)); } if (posSides.Count == 0) { continue; } entranceSide = GenerationRandom.RandomFromList(posSides); pos = new Vec2i(plot.Bounds.X, plot.Bounds.Y); } else if (x == 0 && z == 1) { if (sideHasPath[3]) { posSides.Add(new Vec2i(0, 1)); } if (sideHasPath[0]) { posSides.Add(new Vec2i(-1, 0)); } if (posSides.Count == 0) { continue; } entranceSide = GenerationRandom.RandomFromList(posSides); pos = new Vec2i(plot.Bounds.X + 2, plot.Bounds.Y + plot.Bounds.Height - desHeight); } else if (x == 1 && z == 1) { if (sideHasPath[3]) { posSides.Add(new Vec2i(0, 1)); } if (sideHasPath[1]) { posSides.Add(new Vec2i(1, 0)); } if (posSides.Count == 0) { continue; } entranceSide = GenerationRandom.RandomFromList(posSides); pos = new Vec2i(plot.Bounds.X + plot.Bounds.Width - desWidth, plot.Bounds.Y + plot.Bounds.Height - desHeight); } else if (x == 1 && z == 0) { if (sideHasPath[2]) { posSides.Add(new Vec2i(0, -1)); } if (sideHasPath[1]) { posSides.Add(new Vec2i(1, 0)); } if (posSides.Count == 0) { continue; } entranceSide = GenerationRandom.RandomFromList(posSides); pos = new Vec2i(plot.Bounds.X + plot.Bounds.Width - desWidth, plot.Bounds.Y); } Recti curBound = new Recti(pos.x, pos.z, desWidth, desHeight); bool intersect = false; foreach (Recti ri in bounds) { if (ri != null) { if (ri.Intersects(curBound)) { intersect = true; } } } if (intersect) { continue; } bounds[x, z] = curBound; BuildingGenerationPlan curCorn = new BuildingGenerationPlan() { BuildingPlan = bps[startIndex + j], MaxWidth = maxWidth, MaxHeight = maxHeight, EntranceSide = entranceSide, DesiredSize = new Vec2i(desWidth, desHeight) }; Building build = BuildingGenerator.CreateBuilding(GenerationRandom, out BuildingVoxels vox, curCorn); Recti r = AddBuilding(build, vox, pos); if (r != null) { BuildingPlots.Add(r); j++; } } } } return(j); }
public static House GenerateHouse(GenerationRandom genRan, House house, out BuildingVoxels vox, BuildingGenerationPlan plan) { return(GenerateShack(genRan, house, out vox, plan)); }
/// <summary> /// Generates the simplest type of house - a shack /// A shack is made of either (cobble?) stone or wood, /// it consists of only 1 room, with basic objects inside (bed, chair, table) /// </summary> /// <param name="house"></param> /// <param name="vox"></param> /// <returns></returns> public static House GenerateShack(GenerationRandom genRan, House house, out BuildingVoxels vox, BuildingGenerationPlan plan) { vox = new BuildingVoxels(house.Width, World.ChunkHeight, house.Height); Tile[,] floor = new Tile[house.Width, house.Height]; BuildingGenerator.BuildBoundingWallRect(vox, house.Width, house.Height, 6, Voxel.wood); //BuildingGenerator.ConnectBoundingWall(vox, house.BoundingWall, Voxel.wood, 5); BuildingGenerator.SetTiles(floor, 0, 0, house.Width - 1, house.Height - 1, Tile.STONE_FLOOR); house.SetBuilding(floor); BuildingGenerator.ChooseEntrancePoint(genRan, vox, house, plan); BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: true); BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: true); BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: false); BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: false); BuildingGenerator.AddWindow(genRan, vox, house, size: genRan.RandomInt(1, 4), autoReattempt: false); house.InsideWallPoints = BuildingGenerator.FindInsideWallBoundryPoints(vox, house); /*foreach (Vec2i v in house.InsideWallPoints) * { * //house.AddObjectReference(new Chest().SetPosition(v)); * WorldObjectData bed = new Bed().SetPosition(v); * bed.SetRotation(Vec2i.Angle(Vec2i.Forward, BuildingGenerator.GetWallPointDirection(house, v))); * if(!house.ObjectIntersects(bed)) * house.AddObjectReference(bed); * }*/ BuildingGenerator.PlaceObjectAgainstWall(genRan, new DoubleBed(), 0, vox, house, .3f, distToEntr: 4, attemptsCount: 40); BuildingGenerator.PlaceObjectAgainstWall(genRan, new Chest(), 0, vox, house, 0.1f, distToEntr: 3, attemptsCount: 40); for (int i = 0; i < house.BoundingWall.Length; i++) { BuildingGenerator.PlaceObjectAgainstWall(genRan, new WallTorch(), 1.5f, vox, house, 0f, requireWallBacking: true); } house.AddExternalObject(new BuildingInternalNoWalkFloor(new Vector3(1, 0, 1), new Vector3(house.Width - 2, 5, house.Height - 2))); BuildingGenerator.AddRoof(genRan, vox, house, Voxel.thatch); BuildingSubworldBuilder b = new BuildingSubworldBuilder(house, vox, plan); b.CreateSubworld(); //ChunkData[,] subChunks = new ChunkData[1, 1]; return(house); }
public static Tavern GenerateTavern(GenerationRandom genRan, Tavern tavern, out BuildingVoxels vox, BuildingGenerationPlan plan) { vox = new BuildingVoxels(tavern.Width, World.ChunkHeight, tavern.Height); BuildingGenerator.BuildBoundingWallRect(vox, tavern.Width, tavern.Height, 6, Voxel.wood); BuildingGenerator.ChooseEntrancePoint(genRan, vox, tavern, plan); Tile[,] tileMap = new Tile[tavern.Width, tavern.Height]; BuildingGenerator.SetTiles(tileMap, 0, 0, tavern.Width, tavern.Height, Tile.WOOD_FLOOR); tavern.SetBuilding(tileMap); BuildingGenerator.AddWindow(genRan, vox, tavern, autoReattempt: true); BuildingGenerator.AddWindow(genRan, vox, tavern, autoReattempt: true); BuildingGenerator.AddWindow(genRan, vox, tavern, autoReattempt: true); BuildingGenerator.AddWindow(genRan, vox, tavern, autoReattempt: false); BuildingGenerator.AddWindow(genRan, vox, tavern, autoReattempt: false); FirePlace fp = new FirePlace(); BuildingGenerator.PlaceObjectAgainstWall(genRan, fp, 0, vox, tavern, 0, true, 4, true, 20); BuildingGenerator.PlaceObjectAgainstWall(genRan, new WallTorch(), 1.5f, vox, tavern, 0, true, 2); NPCJob[] jobs = new NPCJob[] { new NPCJobMerchant(tavern, "Tavern Keep"), new NPCJobMerchant(tavern, "Tavern Keep") }; tavern.SetWorkBuildingData(new WorkBuildingData(jobs)); BuildingGenerator.AddRoof(genRan, vox, tavern, Voxel.thatch); return(tavern); }