public static float DistanceSqr(Vector2i a, Vector2i b) { return(Vector2i.DistanceSqr(a, b)); }
/// <summary> /// Runs the generator and returns the spaces in the generated entrance. /// </summary> /// <param name="rooms"> /// The rooms that were generated. Used to choose a place to place an entrance. /// </param> /// <param name="theMap"> /// The map that new units are being generated into. /// </param> /// <param name="unitsToKeep"> /// The units to keep alive in the map, indexed by their ID's. /// Pass "null" if new units should be generated from scratch. /// </param> public List <Vector2i> Generate(Map theMap, EtMGame.WorldSettings genSettings, List <Room> rooms, int nThreads, int seed, UlongSet unitsToKeep = null) { //Choose a room and place the level's "entrance" into the middle of it. List <Vector2i> entranceSpaces = new List <Vector2i>(); { PRNG roomPlacer = new PRNG(unchecked (seed * 8957)); Vector2i entrance = rooms[roomPlacer.NextInt() % rooms.Count].OriginalBounds.Center; entrance = new Vector2i(Mathf.Clamp(entrance.x, 1, genSettings.Size - 2), Mathf.Clamp(entrance.y, 1, genSettings.Size - 2)); //Carve a small circle out of the map for the entrance. const float entranceRadius = 1.75f, entranceRadiusSqr = entranceRadius * entranceRadius; int entranceRadiusCeil = Mathf.CeilToInt(entranceRadius); Vector2i entranceRegionMin = entrance - new Vector2i(entranceRadiusCeil, entranceRadiusCeil), entranceRegionMax = entrance + new Vector2i(entranceRadiusCeil, entranceRadiusCeil); entranceRegionMin = new Vector2i(Mathf.Clamp(entranceRegionMin.x, 0, genSettings.Size - 1), Mathf.Clamp(entranceRegionMin.y, 0, genSettings.Size - 1)); entranceRegionMax = new Vector2i(Mathf.Clamp(entranceRegionMax.x, 0, genSettings.Size - 1), Mathf.Clamp(entranceRegionMax.y, 0, genSettings.Size - 1)); foreach (Vector2i entranceSpace in new Vector2i.Iterator(entranceRegionMin, entranceRegionMax + 1)) { if (entrance.DistanceSqr(entranceSpace) < entranceRadiusSqr) { entranceSpaces.Add(entranceSpace); theMap.Tiles[entranceSpace] = GameLogic.TileTypes.Empty; } } } //If we weren't given any units to place, generate some. if (unitsToKeep == null) { unitsToKeep = new UlongSet(); //Find or create the PlayerGroup. var playerGroup = GameLogic.Groups.PlayerGroup.Get(theMap); //Generate a certain number of player units. PRNG prng = new PRNG(seed); for (int i = 0; i < NStartingChars; ++i) { //PlayerChar's have 3 stats to randomize. //Distribute "points" among them randomly. //Prefer energy, then food, then strength. float totalPoints = StartingStatAbilities; float p = prng.NextFloat() * Math.Min(1.0f, totalPoints); float energy = p; totalPoints -= p; p = prng.NextFloat() * Math.Min(1.0f, totalPoints); float food = p; totalPoints -= p; float strength = totalPoints; energy = Mathf.Lerp(PlayerConsts.MinStart_Energy, PlayerConsts.MaxStart_Energy, energy); food = Mathf.Lerp(PlayerConsts.MinStart_Food, PlayerConsts.MaxStart_Food, food); strength = Mathf.Lerp(PlayerConsts.MinStart_Strength, PlayerConsts.MaxStart_Strength, strength); var gender = (i % 2 == 0) ? GameLogic.Units.Player_Char.Personality.Genders.Male : GameLogic.Units.Player_Char.Personality.Genders.Female; PlayerChar chr = new PlayerChar( theMap, playerGroup.ID, food, energy, strength, 1.0f, GameLogic.Units.Player_Char.Personality.GenerateName(gender, prng.NextInt()), gender); theMap.AddUnit(chr); unitsToKeep.Add(chr.ID); } } //Position the units. UnityEngine.Assertions.Assert.IsTrue(entranceSpaces.Count > 0); int unitsPerSpace = unitsToKeep.Count / entranceSpaces.Count; int unitI = 0, posI = 0; foreach (Unit unit in unitsToKeep.Select(id => theMap.GetUnit(id))) { unit.Pos.Value = entranceSpaces[posI]; unitI += 1; if (unitI >= unitsPerSpace) { unitI = 0; posI = (posI + 1) % entranceSpaces.Count; } } return(entranceSpaces); }