/// <summary> /// Places a roof over the specified building. /// The roof will only cover the tile specified by 'roofTileID'. If this is null, /// then a roof over the total building will be created /// </summary> /// <param name="vox"></param> /// <param name="build"></param> /// <param name="roofTileID"></param> public static void AddRoof(GenerationRandom genRan, BuildingVoxels vox, Building build, Voxel roofVox, int roofStartY = 5, Tile roofTileReplace = null) { if (roofTileReplace == null) { Vec2i dir = genRan.RandomQuadDirection(); dir.x = Mathf.Abs(dir.x); dir.z = Mathf.Abs(dir.z); Vec2i start = new Vec2i(build.Width / 2 * dir.x, build.Height / 2 * dir.z); Vec2i end = start + new Vec2i(dir.z * build.Width, dir.x * build.Height); LineI t = new LineI(start, end); float maxDist = Mathf.Max(t.Distance(new Vec2i(0, 0)), t.Distance(new Vec2i(build.Width - 1, 0)), t.Distance(new Vec2i(0, build.Height - 1)), t.Distance(new Vec2i(build.Width - 1, build.Height - 1))); int maxHeight = genRan.RandomInt(4, 6); float scale = maxHeight / (maxDist + 1); //float scale = 0.7f; for (int x = 0; x < build.Width; x++) { for (int z = 0; z < build.Height; z++) { int height = (int)Mathf.Clamp((maxDist - t.Distance(new Vec2i(x, z)) + 1) * scale, 1, World.ChunkHeight - 1); for (int y = 0; y < height; y++) { vox.AddVoxel(x, Mathf.Clamp(roofStartY + y, 0, World.ChunkHeight - 1), z, roofVox); } } } } }
public void SetVoxels(int x, int y, int z, BuildingVoxels vox) { int cx = WorldToChunk(x); int cz = WorldToChunk(z); for (int x_ = 0; x_ < vox.Width; x_++) { for (int z_ = 0; z_ < vox.Depth; z_++) { int tx = (x_ + x) % World.ChunkSize; int tz = (z_ + z) % World.ChunkSize; //If tx or tz are 0, then cz must have changed - update it if (tx == 0) { cx = (WorldToChunk(x + x_)); } if (tz == 0) { cz = (WorldToChunk(x + x_)); } for (int y_ = 0; y_ < vox.Height; y_++) { ChunkVoxels[cx, cz].SetVoxelNode(tx, y_ + y, tz, vox.GetVoxelNode(x_, y_, z_)); } } } }
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); }
public void CalculateSpawnableTiles(BuildingVoxels vox) { SpawnableTiles = new List <Vec2i>(); for (int x = 0; x < Width; x++) { for (int z = 0; z < Height; z++) { if (vox.GetVoxelNode(x, 0, z).Voxel != Voxel.none) { continue; } bool canPlace = true; foreach (WorldObjectData obj in InternalObjects) { if (obj.IntersectsPoint(new Vec2i(x, z))) { canPlace = false; break; } } if (canPlace) { if (BuildingSubworld != null) { SpawnableTiles.Add(new Vec2i(x, z)); } else { SpawnableTiles.Add(new Vec2i(x, z) + WorldPosition); } } } } }
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(); } } }
public static Vec2i[] FindInsideWallBoundryPoints(BuildingVoxels vox, Building build, Tile groundTile = null) { Vec2i[] dirs = new Vec2i[] { new Vec2i(-1, 0), new Vec2i(1, 0), new Vec2i(0, 1), new Vec2i(0, -1) }; List <Vec2i> wallPoints = new List <Vec2i>(); for (int x = 1; x < build.Width - 1; x++) { for (int z = 1; z < build.Height - 1; z++) { //If the current tile is not defined as a ground tile, we do not include this point if (groundTile != null && build.BuildingTiles[x, z] != groundTile) { continue; } for (int i = 0; i < 4; i++) { int x_ = dirs[i].x + x; int z_ = dirs[i].z + z; Vec2i v_ = new Vec2i(x, z); if (vox.GetVoxel(x_, 0, z_) != Voxel.none && !wallPoints.Contains(v_)) { wallPoints.Add(v_); } } } } return(wallPoints.ToArray()); }
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 ChooseRandomEntrance() public static void BuildBoundingWallRect(BuildingVoxels vox, int width, int depth, int wallHeight, Voxel wallVox) { for (int y = 0; y < wallHeight; y++) { for (int x = 0; x < width; x++) { vox.SetVoxel(x, y, 0, wallVox); vox.SetVoxel(x, y, depth - 1, wallVox); } for (int z = 0; z < depth; z++) { vox.SetVoxel(0, y, z, wallVox); vox.SetVoxel(width - 1, y, z, wallVox); } } }
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); } }
/// <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 bool AddObject(Building build, BuildingVoxels vox, WorldObjectData obj, bool force = false) { if (force) { build.AddInternalObject(obj); return(true); } else { //Iterate all objects in the building and check for intersection. foreach (WorldObjectData obj_ in build.GetBuildingInternalObjects()) { //If they intersect, then we cannot place this object. if (obj_.Intersects(obj)) { return(false); } } //Find the integer bounds Recti bounds = obj.CalculateIntegerBounds(); int yMin = (int)obj.Position.y; int yMax = yMin + (int)obj.Size.y; //Iterate the voxel position of the object bounds. for (int x = bounds.X; x < bounds.X + bounds.Width; x++) { for (int z = bounds.Y; z < bounds.Y + bounds.Height; z++) { for (int y = yMin; y < yMax; y++) { //If any single voxel is non-none, then we cannot place the object here. if (vox.GetVoxel(x, y, z) != Voxel.none) { return(false); } } } } build.AddInternalObject(obj); return(true); } }
public static void ConnectBoundingWall(BuildingVoxels vox, Vec2i[] bounds, Voxel voxel, int wallHeight = 6) { for (int i = 0; i < bounds.Length; i++) { Vec2i a = bounds[i]; Vec2i b = bounds[(i + 1) % bounds.Length]; int x = a.x; int z = a.z; int xDir = (int)Mathf.Sign(b.x - a.x); int zDir = (int)Mathf.Sign(b.z - a.z); while (!(x == b.x && z == b.z)) { for (int y = 0; y < wallHeight; y++) { vox.SetVoxel(x, y, z, voxel); } //data[x, z] = copy.Copy(globalPos + new Vec2i(x, z)); int dx = (int)Mathf.Abs(b.x - x); int dz = (int)Mathf.Abs(b.z - z); if (dx > dz) { x += xDir; } else if (dz > dx) { z += zDir; } else { x += xDir; z += zDir; } } } }
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 void AddBuilding(Building b, BuildingVoxels vox, Vec2i pos) { float minHeight = 0; //SetTiles(pos.x, pos.z, b.Width, b.Height, b.BuildingTiles); for (int x = 0; x < b.Width; x++) { for (int z = 0; z < b.Height; z++) { int cx = WorldToChunk(x); int cz = WorldToChunk(z); int deltaHeight = ChunkBases != null ? (int)(minHeight - ChunkBases[cx, cz].Height) : 0; SetTile(x + pos.x, z + pos.z, b.BuildingTiles[x, z]); SetHeight(x + pos.x, z + pos.z, minHeight); for (int y = 0; y < vox.Height; y++) { VoxelNode voxNode = vox.GetVoxelNode(x, y, z); if (voxNode.IsNode) { //Debug.Log("Adding vox node: " + voxNode); SetVoxelNode(x + pos.x, y, z + pos.z, vox.GetVoxelNode(x, y, z)); } } } } foreach (WorldObjectData obj in b.GetBuildingExternalObjects()) { obj.SetPosition(obj.Position + pos.AsVector3()); //We (should) already have checked for object validity when creating the building AddObject(obj, true); } }
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); }
/// <summary> /// /// </summary> /// <param name="genRan">The RNG used for this building</param> /// <param name="obj">The object to place in the building</param> /// <param name="height">The height above the ground the object should sit</param> /// <param name="vox">The voxel data of this building. Only required if 'requireWallBacking' is true</param> /// <param name="build">The building to place the object in</param> /// <param name="distFromWall">The distance from a wall the object should be placed</param> /// <param name="wallIndex">Defines the wall we should attempt to place this object on. The 'i'th wall defines the wall /// connecting build.BoundingWall[i] -> build.BoundingWall[i+1]. If left as default value (-1), an index will be randomly generated</param> /// <param name="requireWallBacking">If true, then we will search for a point on the wall that is backed against a wall. /// Used to stop certain objects being placed in front of windows</param> /// <param name="forcePlace">If true, then we do not check for intersection with other objects in the building</param> /// <param name="attemptsCount">The number of attempts made to place the object on this wall</param> /// <returns>True if object is placed sucesfully, false otherwise</returns> public static bool PlaceObjectAgainstWall(GenerationRandom genRan, WorldObjectData obj, float height, BuildingVoxels vox, Building build, float distFromWall = 0, bool requireWallBacking = false, int distToEntr = 2, bool forcePlace = false, int attemptsCount = 5) { if (build.InsideWallPoints == null) { build.InsideWallPoints = FindInsideWallBoundryPoints(vox, build); } //Check attempts count attemptsCount--; if (attemptsCount == 0) { return(false); } float wallDisp = genRan.Random(); //Define the position as the start pos + lambda*dir //Select a random position from all wall points Vec2i pos = genRan.RandomFromArray(build.InsideWallPoints); //If too close to entrance, try another placement if (build.Entrance != null && pos.QuickDistance(build.Entrance) < distToEntr * distToEntr) { return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount)); } //If the object is too close to any of the corners, try again foreach (Vec2i v in build.BoundingWall) { if (v.QuickDistance(pos) < 2) { return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount)); } } Vec2i faceDirection = GetWallPointDirection(build, pos); //If we require a backing wall, we check the position if (requireWallBacking) { Vec2i wPos = pos - faceDirection; for (int y = 0; y < 4; y++) { VoxelNode vn = vox.GetVoxelNode(wPos.x, y, wPos.z); //If there is no node (nothing set) then this position is not valid if (!vn.IsNode) { return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount)); } if (vn.Voxel == Voxel.glass || vn.Voxel == Voxel.none) { return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount)); } } } Vector3 finPos = pos.AsVector3() + faceDirection.AsVector3() * distFromWall + Vector3.up * height; float rotation = Vec2i.Angle(Vec2i.Forward, faceDirection); obj.SetPosition(finPos).SetRotation(rotation); if (!forcePlace) { foreach (WorldObjectData obj_ in build.GetBuildingExternalObjects()) { if (obj.Intersects(obj_)) { return(PlaceObjectAgainstWall(genRan, obj, height, vox, build, distFromWall, requireWallBacking, distToEntr, forcePlace, attemptsCount)); } } } //obj.SetPosition(finPos); build.AddInternalObject(obj); return(true); }
public static House GenerateHouse(GenerationRandom genRan, House house, out BuildingVoxels vox, BuildingGenerationPlan plan) { return(GenerateShack(genRan, house, out vox, plan)); }
private static void PlaceOutsideObjects(GenerationRandom genRan, Blacksmith smith, BuildingVoxels vox, Vec2i outMin, Vec2i outMax) { List <WorldObjectData> toPlace = new List <WorldObjectData>(new WorldObjectData[] { new Anvil(), new Anvil() }); bool isFinished = false; while (!isFinished) { WorldObjectData toPlaceCur = toPlace[0]; toPlace.RemoveAt(0); Vector3 pos = genRan.RandomVector3(outMin.x, outMax.x, 0, 0, outMin.z, outMax.z); toPlaceCur.SetPosition(pos); while (!BuildingGenerator.AddObject(smith, vox, toPlaceCur)) { pos = genRan.RandomVector3(outMin.x, outMax.x, 0, 0, outMin.z, outMax.z); toPlaceCur.SetPosition(pos); } if (toPlace.Count == 0) { isFinished = true; } } }
/// <summary> /// Adds the building to the settlement /// </summary> /// <param name="b"></param> /// <param name="vox"></param> /// <param name="pos"></param> /// <returns></returns> public Recti AddBuilding(Building b, BuildingVoxels vox, Vec2i pos) { if (!IsAreaFree(pos.x, pos.z, b.Width, b.Height)) { return(null); } int nodeX = Mathf.FloorToInt(((float)pos.x) / NodeSize); int nodeZ = Mathf.FloorToInt(((float)pos.z) / NodeSize); int nodeWidth = Mathf.CeilToInt(((float)b.Width) / NodeSize); int nodeHeight = Mathf.CeilToInt(((float)b.Height) / NodeSize); for (int x = nodeX; x < nodeX + nodeWidth; x++) { for (int z = nodeZ; z < nodeZ + nodeHeight; z++) { BuildingMap[x, z] = true; } } Recti bo = new Recti(pos.x - 1, pos.z - 1, b.Width + 2, b.Height + 2); foreach (Recti bound in BuildingPlots) { if (bo.Intersects(bound)) { return(null); } } int height = (int)Mathf.FloorToInt(FlattenArea(pos.x - 1, pos.z - 1, b.Width + 2, b.Height + 2)); BuildingPlots.Add(bo); //Debug.Log("Adding building " + b); //SetTiles(pos.x, pos.z, b.Width, b.Height, b.BuildingTiles); for (int x = 0; x < b.Width; x++) { for (int z = 0; z < b.Height; z++) { SetTile(x + pos.x, z + pos.z, b.BuildingTiles[x, z]); //SetHeight(x + pos.x, z + pos.z, maxHeight); for (int y = 0; y < vox.Height; y++) { SetVoxelNode(x + pos.x, height + y, z + pos.z, vox.GetVoxelNode(x, y, z)); } } } foreach (WorldObjectData obj in b.GetBuildingExternalObjects()) { //We must set the object to have coordinates based on the settlement, //such that the object is added to the correct chunk. obj.SetPosition(obj.Position + pos.AsVector3()); //We (should) already have checked for object validity when creating the building AddObject(obj, true); } Vec2i wPos = pos + BaseTile; Vec2i cPos = World.GetChunkPosition(wPos); //Debug.Log("Calculating tiles!!!"); b.SetPositions(BaseTile, pos); //if (b.BuildingSubworld != null) // AddObject(b.ExternalEntranceObject as WorldObjectData, true); // World.Instance.AddSubworld(b.BuildingSubworld); b.CalculateSpawnableTiles(vox); Buildings.Add(b); //PathNodes.Add(b.Entrance); return(bo); }
public static bool AddWindow(GenerationRandom genRan, BuildingVoxels vox, Building build, int wallIndex = -1, int size = 2, int height = 1, bool autoReattempt = true, int reattemptCount = 3) { reattemptCount--; if (reattemptCount == 0) { return(false); } //if default index, we choose one randomly if (wallIndex == -1) { wallIndex = genRan.RandomInt(0, build.BoundingWall.Length); } int wp1 = (wallIndex + 1) % build.BoundingWall.Length; Vec2i dif = build.BoundingWall[wp1] - build.BoundingWall[wallIndex]; int absX = Mathf.Abs(dif.x); int signX = (int)Mathf.Sign(dif.x); int absZ = Mathf.Abs(dif.z); int signZ = (int)Mathf.Sign(dif.z); Vec2i dir = new Vec2i(absX == 0?0:signX, absZ == 0 ? 0 : signZ); int len = absX + absZ; //if the selected wall has a length that is not large enough to house the window, if (len < size + 4) { if (autoReattempt) { return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount)); } //Then we do not build a window return(false); } int dx = dir.x == 0 ? 0 : genRan.RandomInt(1, absX - size - 2); int dz = dir.z == 0 ? 0 : genRan.RandomInt(1, absZ - size - 2); Vec2i dPos = dir * (dx + dz); Vec2i start = build.BoundingWall[wallIndex]; Vec2i cur = start + dPos; //If the building has an entrance, we iterate all window points //to make sure we aren't breaking a door if (build.Entrance != null) { //If we are too close to the door if (cur.QuickDistance(build.Entrance) < (size + 1) * (size + 1)) { if (autoReattempt) { return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount)); } return(false); } else { for (int i = 0; i < size; i++) { cur = start + dPos + (dir * i); if (cur.x > 0 && cur.z > 0 && cur.x < build.Width && cur.z < build.Height) { if (vox.GetVoxel(cur.x, 2, cur.z) == Voxel.glass) { if (autoReattempt) { return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount)); } return(false); } } else { if (autoReattempt) { return(AddWindow(genRan, vox, build, wp1, size, height, autoReattempt, reattemptCount)); } return(false); } } } } cur = start + dPos; Vector3 position = (cur - dir).AsVector3() + Vector3.up; Vector3 scale = new Vector3(0.5f, 2, (dir.x + dir.z) * size); float rotation = Mathf.Acos(dir.z) * Mathf.Rad2Deg; //GlassWindow window = new GlassWindow(position, scale, rotation); //build.AddObjectReference(window); for (int i = -1; i <= size; i++) { cur = start + dPos + dir * i; for (int y = 1; y <= 2 + height; y++) { if (i < 0 || i >= size || y == 1 || y == 2 + height) { vox.AddVoxel(cur.x, y, cur.z, Voxel.glass); } else { vox.ClearVoxel(cur.x, y, cur.z); vox.SetVoxel(cur.x, y, cur.z, Voxel.glass); } //vox.Add(cur.x, y, cur.z, Voxel.none); } } return(true); }