/// <summary> /// Generates a broken temple pillar. Only places between vitric sand. Automatically scans for crystals, and returns false if a crystal is in the way. /// </summary> /// <param name="x">Center X position.</param> /// <param name="y">Y position. Can be anywhere between a ceiling and floor; will generate appropriately.</param> /// <returns>True if a pillar was successfully placed within an area</returns> public static bool GenPillar(int x, int y) { int ceil = FindTypeUp(x, y, VitricBiome.Y - 20, TileType <VitricSand>(), TileType <VitricSoftSand>()); int floor = FindType(x, y, VitricBiome.Bottom + 20, TileType <VitricSand>(), TileType <VitricSoftSand>()); if (ceil == -1 || floor == -1 || ceil >= floor) { return(false); //If there's an invalid ceiling or floor, or if the floor is above or on the ceiling, kill } int height = floor - ceil; //Height of pillar if (height < 7 || height > 50) { return(false); //If it's too short or too tall } int wid = genRand.Next(3, 6); //Width of pillar int GetHeight(int xPos) => Math.Abs(ceil - FindTypeUp(xPos, y, VitricBiome.Y - 20, TileType <VitricSand>(), TileType <VitricSoftSand>())); int GetDepth(int xPos) => Math.Abs(floor - FindType(xPos, y, VitricBiome.Y - 20, TileType <VitricSand>(), TileType <VitricSoftSand>())); for (int i = -wid; i < wid + 1; ++i) //Checks for crystals. If there's a crystal, kill this pillar before it gens { if (Helper.ScanForTypeDown(x + i, y, TileType <VitricLargeCrystal>(), 100) || Helper.ScanForTypeDown(x + i, y, TileType <VitricSmallCrystal>(), 100)) { return(false); //Crystal found, can't place here } if (GetHeight(x + i) - 30 > GetHeight(x - wid) || GetHeight(x + i) - 30 > GetHeight(x + wid)) { return(false); //Large height differencial found, can't place } if (GetDepth(x + i) + 30 < GetDepth(x - wid) || GetDepth(x + i) + 30 < GetDepth(x + wid)) { return(false); //Large height differencial found, can't place } } for (int i = -wid; i < wid + 1; ++i) { //Tile placement int depth = genRand.Next(2) + 1; if (Math.Abs(i) == wid || Math.Abs(i) == wid - 2) { depth = (int)Math.Ceiling(height / 4f) + genRand.Next((int)Math.Ceiling(-height / 6f), (int)Math.Ceiling(height / 6f)); } if (Math.Abs(i) == wid - 1) { depth = (int)Math.Ceiling(height / 3f) + genRand.Next((int)Math.Ceiling(-height / 6f), (int)Math.Ceiling(height / 6f)); } int ceilingY = FindTypeUp(x + i, y, VitricBiome.Y - 20, TileType <VitricSand>(), TileType <VitricSoftSand>()); int floorY = FindType(x + i, y, VitricBiome.Bottom + 20, TileType <VitricSand>(), TileType <VitricSoftSand>()); for (int j = 0; j < depth; ++j) { KillTile(x + i, ceilingY + j, false, false, true); PlaceTile(x + i, ceilingY + j, TileType <AncientSandstone>(), true, false); KillTile(x + i, floorY - j, false, false, true); PlaceTile(x + i, floorY - j, TileType <AncientSandstone>(), true, false); } //Wall placement depth = (int)Math.Ceiling(height / 2f) + 2; if (Math.Abs(i) >= wid) { depth = genRand.Next(2) + 1; } if (Math.Abs(i) == wid - 2) { depth = (int)Math.Ceiling(height / 3f) + genRand.Next((int)Math.Ceiling(-height / 6f), (int)Math.Ceiling(height / 4f)); } if (Math.Abs(i) == wid - 1) { depth = (int)Math.Ceiling(height / 4f) + genRand.Next((int)Math.Ceiling(-height / 6f), (int)Math.Ceiling(height / 6f)); } for (int j = 0; j < depth; ++j) { KillWall(x + i, ceilingY + j, false); PlaceWall(x + i, ceilingY + j, WallType <AncientSandstoneWall>(), true); KillWall(x + i, floorY - j, false); PlaceWall(x + i, floorY - j, WallType <AncientSandstoneWall>(), true); } } RuinedPillarPositions.Add(new Point(x, y)); return(true); }
/// <summary>Generates ruins using premade structures, or using the GenPillar method.</summary> /// <param name="validGround"></param> private static void GenRuins() { Point16[] ruinedHouseSizes = new Point16[6] { new Point16(8, 7), new Point16(14, 7), new Point16(12, 7), new Point16(10, 6), new Point16(12, 5), new Point16(14, 7) }; int failCount = 0; for (int i = 0; i < 6; ++i) { if (failCount > 120) { break; //To many fails, stop } int x = VitricBiome.X + VitricSlopeOffset + genRand.Next(VitricBiome.Width - (VitricSlopeOffset * 2)); while (x > VitricBiome.X + VitricBiome.Width / 2 - 71 && x < VitricBiome.X + VitricBiome.Width / 2 + 70) { x = VitricBiome.X + genRand.Next(VitricBiome.Width); } int ty = genRand.Next(ruinedHouseSizes.Length); Point16 size = ruinedHouseSizes[ty]; int y = FindType(x, (VitricBiome.Y + 38) + (genRand.Next((int)(VitricBiome.Height / 3.2f))), -1, ValidGround) + genRand.Next(2); if ((x < VitricBiome.X + VitricBiome.Width / 2 - 71 || x > VitricBiome.X + VitricBiome.Width / 2 + 70) && Helper.CheckAirRectangle(new Point16(x, y - size.Y), new Point16(size.X, size.Y - 3)) && //ScanRectangle(x, y, size.X, size.Y) < 10 ValidGround.Any(v => v == Main.tile[x + 1, y].type) && ValidGround.Any(v => v == Main.tile[x + size.X - 1, y].type)) { StructureHelper.StructureHelper.GenerateStructure("Structures/Vitric/VitricTempleRuins_" + ty, new Point16(x, y - size.Y), StarlightRiver.Instance); } else { i--; failCount++; continue; } } failCount = 0; for (int i = 0; i < 4; ++i) { if (failCount > 60) { break; //Too many fails, stop } int x = VitricBiome.X + VitricSlopeOffset + genRand.Next(VitricBiome.Width - (VitricSlopeOffset * 2)); while (x > VitricBiome.Center.X - 71 && x < VitricBiome.Center.X + 70) { x = VitricBiome.X + VitricSlopeOffset + genRand.Next(VitricBiome.Width - (VitricSlopeOffset * 2)); } int y = VitricBiome.Y + genRand.Next(VitricBiome.Height); while (Main.tile[x, y].active()) { y = VitricBiome.Y + genRand.Next(VitricBiome.Height); } if (RuinedPillarPositions.Any(v => Vector2.Distance(v.ToVector2(), new Vector2(x, y)) < 40) || !GenPillar(x, y)) { i--; failCount++; } } }
/// <summary>Generates a large island at X/Y.</summary> /// <param name="x">X position.</param> /// <param name="y">Y position.</param> private static void CreateIsland(int x, int y, bool small = false) { int wid = genRand.Next(32, 42); if (small) { wid = genRand.Next(10, 18); } int top = 5; int depth = 2; bool peak = false; int peakEnd = 0; int peakStart = 0; int offset = 0; for (int i = x - (int)(wid / 2f); i < x + (wid / 2f); ++i) { if (i == x - (int)(wid / 2f) + 1) { top++; } else if (i == (x + (int)(wid / 2f)) - 1) { top--; } if (!peak) { if (depth <= 2) { depth += genRand.Next(2); } else { depth += genRand.Next(-1, 2); } if (genRand.Next(3) == 0) { peak = true; peakStart = i; peakEnd = i + genRand.Next(3, 8); if (peakEnd > (x + (wid / 2f)) - 1) { peakEnd = (int)(x + (wid / 2f)) - 1; } } } else { int dist = peakEnd - i; int dif = peakEnd - peakStart; int deep = (7 - dif); if (dist > (int)(dif / 2f)) { depth += genRand.Next(deep, deep + 2); } else { depth -= genRand.Next(deep, deep + 2); } if (x >= peakEnd) { peak = false; } } if (i % 4 == 0) { if (i < x) { top += genRand.Next(2); } else { top -= genRand.Next(2); } } if (i % 8 == 2) { offset += genRand.Next(-1, 2); } if (top < 3) { top = 3; } if (i > x + (wid / 2f) - 4 && depth > 4) { depth--; } if (i > x + (wid / 2f) - 4 && depth > 8) { depth--; } for (int j = y - top + offset; j < y + depth + offset; j++) { int t = j > (y + depth + offset) - 4 ? TileType <VitricSand>() : TileType <VitricSoftSand>(); PlaceTile(i, j, t, false, true); } } //Place crystal if needed if (crystalsPlaced <= (VitricBiome.Width / 240) + 2 && !small) { int tries = 0; while (true) { int cX = x + genRand.Next((int)(wid * -0.60f), (int)(wid * 0.60f)) - 3; int cY = y - 5; while (Main.tile[cX, cY].active()) { cY--; } cY = Math.Max( FindType(cX, cY, -1, ValidGround), FindType(cX + 1, cY, -1, ValidGround) ); if (ValidGround.Any(v => v == Main.tile[cX + 1, cY].type) && ValidGround.Any(v => v == Main.tile[cX + 2, cY].type) && ScanRectangle(cX, cY - 6, 4, 6) < 3) { StructureHelper.StructureHelper.GenerateStructure( "Structures/Vitric/VitricSmallCrystal_" + genRand.Next(2), new Point16(cX, cY - 6), StarlightRiver.Instance ); crystalsPlaced++; break; } else if (tries++ >= 20) { break; } } } else if (small) { // Input variables int spawnAttempts = 30; int cX, cY; // Perform several checks while (spawnAttempts-- > 0) { cX = x + genRand.Next((int)(wid * -0.60f), (int)(wid * 0.60f)) - 3; cY = y - 5; cY = FindType(cX, cY, -1, ValidGround); // If the left side of the crystal isn't valid, // or if the right side is occupied, // skip. if (cY == -1) { continue; } // If there are solid tiles in the way, skip. if (ScanRectangle(cX, cY - 3, 2, 3) > 2) { continue; } // Success! Halve the spawnAttempts count so we don't spam crystals. PlaceTile(cX + 1, cY, Framing.GetTileSafely(cX, cY).type, true, true); Helper.PlaceMultitile(new Point16(cX, cY - 3), TileType <VitricOre>()); spawnAttempts /= 4; } } }
/// <summary>Generates the Vitric Desert under the Underground Desert.</summary> /// <param name="progress"></param> public static void VitricGen(GenerationProgress progress) { progress.Message = "Digging Vitric Desert"; int vitricHeight = 140; ValidGround = new int[] { TileType <VitricSand>(), TileType <VitricSoftSand>() }; //Basic biome information VitricBiome = new Rectangle(UndergroundDesertLocation.X - 80, UndergroundDesertLocation.Y + UndergroundDesertLocation.Height, UndergroundDesertLocation.Width + 150, vitricHeight); int minCeilingDepth = (int)((VitricBiome.Y + (VitricBiome.Height / 2)) - (17f * Math.Log(VitricSlopeOffset - 8))); //Various informational variables - not to be changed int maxCeilingDepth = minCeilingDepth + 7; int minFloorDepth = (int)(VitricBiome.Y + (13f * Math.Log(VitricSlopeOffset - 8))) + (VitricBiome.Height / 2); GenerateBase(minCeilingDepth, maxCeilingDepth, minFloorDepth); for (int x = VitricBiome.Center.X - 35; x <= VitricBiome.Center.X + 36; x++) //Entrance from Desert { for (int y = VitricBiome.Y - 6; y < VitricBiome.Y + 20; y++) { KillTile(x, y); if (y > VitricBiome.Y + 5 && y < VitricBiome.Y + 9) { PlaceTile(x, y, TileType <VitricBossBarrier>(), true, true); } } } for (int y = VitricBiome.Y + 9; y < VitricBiome.Y + VitricBiome.Height - 77; y++) //collision for pillars { PlaceTile(VitricBiome.X + VitricBiome.Width / 2 - 40, y, TileType <VitricBossBarrier>(), false, false); PlaceTile(VitricBiome.X + VitricBiome.Width / 2 + 41, y, TileType <VitricBossBarrier>(), false, false); } VitricIslandLocations = new List <Point>(); //List for island positions int fail = 0; for (int i = 0; i < (VitricBiome.Width / 40) - 1; ++i) { int x; int y; bool repeat = false; do { x = genRand.Next(2) == 0 ? genRand.Next(VitricBiome.X + VitricSlopeOffset + 20, VitricBiome.Center.X - 61) : genRand.Next(VitricBiome.Center.X + 62, VitricBiome.Right - VitricSlopeOffset - 20); y = (maxCeilingDepth + 18) + (genRand.Next((int)(VitricBiome.Height / 2.8f))); if (VitricIslandLocations.Any(v => Vector2.Distance(new Vector2(x, y), v.ToVector2()) < 32) || (x > VitricBiome.X + VitricBiome.Width / 2 - 71 && x < VitricBiome.X + VitricBiome.Width / 2 + 70)) { repeat = true; if (fail++ >= 50) { break; } } else { repeat = false; } }while (repeat); //Gets a valid island position if (fail >= 50) { break; //Could not get a valid position, stop trying } VitricIslandLocations.Add(new Point(x, y)); CreateIsland(x, y); //Adds island pos to list and places island } for (int i = 0; i < 8; ++i) //Mini islands v2, outer only { int x = i <= 2 ? VitricBiome.X + 6 + genRand.Next((int)(VitricSlopeOffset * 1.3f)) : VitricBiome.Right - 6 - genRand.Next((int)(VitricSlopeOffset * 1.3f)); if (i <= 2 && forgeSide == 0) { x += 10; } if (i > 2 && forgeSide == 1) { x -= 10; } int y = genRand.Next(VitricBiome.Y + 22, VitricBiome.Bottom - 50); if (ScanRectangle(x - 13, y - 4, 26, 14) < 8) { CreateIsland(x, y, true); } else { i--; } } //Mini islands throughout main area List <Point> MiniIslandLocations = new List <Point>(); for (int i = 0; i < 20;) //I may or may not be doing this because I find this form of a for loop neat. { int x = genRand.Next(2) == 0 ? genRand.Next(VitricBiome.X + VitricSlopeOffset + 20, VitricBiome.Center.X - 61) : genRand.Next(VitricBiome.Center.X + 62, VitricBiome.Right - VitricSlopeOffset - 20); int y = (maxCeilingDepth + 18) + (genRand.Next((int)(VitricBiome.Height / 2.8f))); if (MiniIslandLocations.Any(v => Vector2.Distance(v.ToVector2(), new Vector2(x, y)) < 1) || ScanRectangle(x - 13, y - 4, 26, 14) > 8) { i++; continue; } else { MiniIslandLocations.Add(new Point(x, y)); } } for (int i = 0; i < MiniIslandLocations.Count; ++i) { if (genRand.NextFloat() > 0.7f) { CreateIsland(MiniIslandLocations[i].X, MiniIslandLocations[i].Y, true); } } fail = 0; for (int i = 0; i < VitricBiome.Width / 160; ++i) { if (fail > 40) { break; } int x = genRand.Next(2) == 0 ? genRand.Next(VitricBiome.X + VitricSlopeOffset + 20, VitricBiome.Center.X - 61) : genRand.Next(VitricBiome.Center.X + 62, VitricBiome.Right - VitricSlopeOffset - 20); int y = (maxCeilingDepth + 20) + (genRand.Next((int)(VitricBiome.Height / 3.2f))); if (Helper.ScanForTypeDown(x, y, TileType <VitricSpike>(), 120)) { y = FindType(x, y, VitricBiome.Bottom + 20, TileType <VitricSpike>()); } else { i--; fail++; continue; } if (!FloorCrystal(x, y)) { i--; fail++; continue; } } //Mini islands progress.Message = "Populating the Vitric"; GenConsistentMiniIslands(); GenSandstonePillars(); RuinedPillarPositions = new List <Point>(); GenRuins(); GenForge(); GenDecoration(); //GenMoss(); GenTemple(); VitricBiome.Y -= 8; //Adjust a bit }