private void AddMonstersToRoomsOnLevelGaussianDistribution(MapInfo mapInfo, int level, IEnumerable <Monster> monster) { //Get the number of rooms var allRoomsAndCorridors = mapInfo.GetRoomIndicesForLevel(level).Except(new List <int> { mapInfo.StartRoom }); var rooms = mapInfo.FilterOutCorridors(allRoomsAndCorridors).ToList(); var candidatePointsInRooms = rooms.Select(room => mapInfo.GetAllPointsInRoomOfTerrain(room, RoomTemplateTerrain.Floor)); var roomsAndPointsInRooms = rooms.Zip(candidatePointsInRooms, Tuple.Create); var monstersToPlaceRandomized = monster.Shuffle().ToList(); int noMonsters = monstersToPlaceRandomized.Count; int noRooms = rooms.Count(); LogFile.Log.LogEntryDebug("No rooms: " + noRooms + " Total monsters to place (level: " + level + "): " + noMonsters, LogDebugLevel.Medium); //Distribution amongst rooms, mostly evenly, scaled by room size var roomMonsterRatio = roomsAndPointsInRooms.Select(rp => Math.Max(0, Gaussian.BoxMuller(5, 3)) * rp.Item2.Count()); double totalMonsterRatio = roomMonsterRatio.Sum(); double ratioToTotalMonsterBudget = noMonsters / totalMonsterRatio; int[] monstersPerRoom = new int[noRooms]; double remainder = 0.0; for (int i = 0; i < noRooms; i++) { double monsterBudget = roomMonsterRatio.ElementAt(i) * ratioToTotalMonsterBudget + remainder; double actualMonstersToPlace = Math.Floor(monsterBudget); double levelBudgetSpent = actualMonstersToPlace; double levelBudgetLeftOver = monsterBudget - levelBudgetSpent; monstersPerRoom[i] = (int)actualMonstersToPlace; remainder = levelBudgetLeftOver; //Any left over monster ratio gets added to the next level up } //Calculate actual number of monster levels placed int totalMonsters = monstersPerRoom.Sum(); LogFile.Log.LogEntryDebug("Total monsters actually placed (level: " + level + "): " + noMonsters, LogDebugLevel.Medium); //Place monsters in rooms Dungeon dungeon = Game.Dungeon; int monsterPos = 0; for (int r = 0; r < noRooms; r++) { int monstersToPlaceInRoom = monstersPerRoom[r]; var candidatePointsInRoom = roomsAndPointsInRooms.ElementAt(r).Item2.Shuffle(); int monstersPlacedInRoom = 0; foreach (var p in candidatePointsInRoom) { if (monsterPos >= monstersToPlaceRandomized.Count) { LogFile.Log.LogEntryDebug("Trying to place too many monsters", LogDebugLevel.High); monsterPos++; break; } Monster mon = monstersToPlaceRandomized[monsterPos]; GiveMonsterStandardItems(mon); bool placedSuccessfully = Game.Dungeon.AddMonster(mon, level, p); if (placedSuccessfully) { monsterPos++; monstersPlacedInRoom++; } if (monstersPlacedInRoom >= monstersToPlaceInRoom) { break; } } } }
private IEnumerable <Monster> CreateGaussianDistributionOfMonsterTypes(List <Tuple <int, Monster> > typesToPlace, int totalMonsters) { int weightAverage = 10; int weightStdDev = 30; var monstersAndWeights = typesToPlace.Select(f => new Tuple <int, Monster>((int)Math.Abs(Gaussian.BoxMuller(weightAverage, weightStdDev)) * f.Item1, f.Item2)); var monsterTypesDistributionExpanded = Enumerable.Range(0, totalMonsters).Select(i => ChooseItemFromWeights <Monster>(monstersAndWeights)); return(monsterTypesDistributionExpanded.Select(m => m.NewCreatureOfThisType())); }