/// <summary> /// Constructor. /// </summary> /// <param name="mapSize">Map size.</param> /// <param name="mapShape">Map shape.</param> /// <param name="landCoverage">Map land coverage.</param> /// <param name="temperature">Map temperature.</param> /// <param name="age">Map age.</param> /// <param name="humidity">Map humidity.</param> /// <param name="playerCivilization">Human player civilization.</param> /// <param name="playerGender">The <see cref="PlayerPivot.Gender"/> value.</param> /// <param name="iaPlayersCount">Number of IA civilizations (except barbarians).</param> /// <param name="randomCityNames">Sets <c>True</c> to active random city names for the human player.</param> /// <exception cref="ArgumentNullException"><paramref name="playerCivilization"/> is <c>Null</c>.</exception> /// <exception cref="ArgumentException"><paramref name="iaPlayersCount"/> invalid.</exception> public EnginePivot(SizePivot mapSize, LandShapePivot mapShape, LandCoveragePivot landCoverage, TemperaturePivot temperature, AgePivot age, HumidityPivot humidity, CivilizationPivot playerCivilization, bool playerGender, int iaPlayersCount, bool randomCityNames) { if (playerCivilization == null) { throw new ArgumentNullException(nameof(playerCivilization)); } iaPlayersCount = iaPlayersCount < 0 ? 0 : iaPlayersCount; if (iaPlayersCount > CivilizationPivot.GetCivilizations(false).Count / (6 - (int)mapSize)) { throw new ArgumentException("The IA players count is too high for this map size !", nameof(iaPlayersCount)); } Map = new MapPivot(mapSize, mapShape, landCoverage, temperature, age, humidity); List <MapSquarePivot> excludedSpots = new List <MapSquarePivot>(); HumanPlayer = new PlayerPivot(this, playerCivilization, false, GetRandomLocation(excludedSpots), playerGender, randomCityNames); var allCivs = CivilizationPivot.GetCivilizations(false); for (int i = 0; i < iaPlayersCount; i++) { CivilizationPivot iaCiv = null; do { iaCiv = allCivs.ElementAt(Tools.Randomizer.Next(0, allCivs.Count)); }while (HumanPlayer.Civilization == iaCiv || _opponentPlayers.Any(ia => ia.Civilization == iaCiv)); _opponentPlayers.Add(new PlayerPivot(this, iaCiv, true, GetRandomLocation(excludedSpots), Tools.Randomizer.Next(0, 2) == 0, false)); } BarbarianPlayer = new PlayerPivot(this, CivilizationPivot.Barbarian, true, null, false, true); // Sets war between every civilizations. for (int i = 0; i < Players.Count - 1; i++) { for (int j = i + 1; j < Players.Count; j++) { Players.ElementAt(i).SwitchPeaceStatusWithOpponent(Players.ElementAt(j)); } } CurrentTurn = 0; }
/// <summary> /// Constructor. /// </summary> /// <param name="mapSize"><see cref="SizePivot"/></param> /// <param name="mapShape"><see cref="LandShapePivot"/></param> /// <param name="landCoverage"><see cref="LandCoveragePivot"/></param> /// <param name="temperature"><see cref="TemperaturePivot"/></param> /// <param name="age"><see cref="AgePivot"/></param> /// <param name="humidity"><see cref="HumidityPivot"/></param> internal MapPivot(SizePivot mapSize, LandShapePivot mapShape, LandCoveragePivot landCoverage, TemperaturePivot temperature, AgePivot age, HumidityPivot humidity) { var continentCount = mapShape == LandShapePivot.Pangaea ? 1 : ( mapShape == LandShapePivot.Continent ? Tools.Randomizer.Next(CONTINENT_COUNT_MIN, CONTINENT_COUNT_MAX + 1) : Tools.Randomizer.Next(ISLAND_COUNT_MIN, ISLAND_COUNT_MAX + 1) ); var landRatio = LAND_COVERAGE_RATIOS[landCoverage]; _huts = new List <HutPivot>(); Height = MINIMAL_HEIGHT * (int)mapSize; Width = Height * RATIO_WIDTH_HEIGHT; GlobalTemperature = temperature; _mapSquareList = new MapSquarePivot[Height, Width]; var continentInfos = new List <List <MapSquarePivot> >(); var boundaries = new List <ContinentBlueprint>(); Action <ContinentBlueprint> SplitX = delegate(ContinentBlueprint contPick) { var splitX = Tools.Randomizer.Next((int)Math.Floor(MIN_SPLIT_RATIO * contPick.Width), (int)Math.Floor(MAX_SPLIT_RATIO * contPick.Width)); boundaries.Add(new ContinentBlueprint(splitX, contPick.Height, contPick.StartX, contPick.StartY)); boundaries.Add(new ContinentBlueprint(contPick.Width - splitX, contPick.Height, contPick.StartX + splitX, contPick.StartY)); }; Action <ContinentBlueprint> SplitY = delegate(ContinentBlueprint contPick) { var splitY = Tools.Randomizer.Next((int)Math.Floor(MIN_SPLIT_RATIO * contPick.Height), (int)Math.Floor(MAX_SPLIT_RATIO * contPick.Height)); boundaries.Add(new ContinentBlueprint(contPick.Width, splitY, contPick.StartX, contPick.StartY)); boundaries.Add(new ContinentBlueprint(contPick.Width, contPick.Height - splitY, contPick.StartX, contPick.StartY + splitY)); }; Action <int, bool> Split = delegate(int pickIndex, bool inY) { var contPick = boundaries[pickIndex]; if (inY) { SplitY(contPick); } else { SplitX(contPick); } boundaries.Remove(contPick); }; List <int> ranges = new List <int>(); var cpt = ISLAND_COUNT_MAX; while (cpt > 1) { ranges.Add(cpt); cpt /= 2; } for (int i = 1; i <= continentCount; i++) { if (boundaries.Count == 0) { boundaries.Add(new ContinentBlueprint(Width, Height, 0, 0)); } else { var nextTypeI = ranges.Where(x => x > boundaries.Count).Min(); Split( Tools.Randomizer.Next(0, nextTypeI - boundaries.Count), ranges.Any(x => x == Math.Sqrt(nextTypeI)) ); } } var cIndex = 0; foreach (var boundary in boundaries) { continentInfos.Add(ConvertContinentBlueprintToMapSquares(landRatio, boundary, cIndex)); cIndex++; } // sets chunks var chunksByType = BiomePivot.ChunkAppearanceBiomes.ToDictionary(b => b, b => new List <List <Tuple <int, int> > >()); var rivers = new List <List <Tuple <int, int> > >(); var huts = new List <Tuple <int, int> >(); foreach (var fullLand in continentInfos) { fullLand.ForEach(msloc => _mapSquareList[msloc.Row, msloc.Column] = msloc); var continentLand = fullLand.Where(ms => !ms.Biome.IsSeaType).ToList(); var chunksCountByType = BiomePivot.ChunkAppearanceBiomes .ToDictionary(b => b, b => b.ChunkSquaresCount(continentLand.Count, CHUNK_SIZE_RATIO, humidity, age)); var topY = continentLand.Min(x => x.Row); var leftX = continentLand.Min(x => x.Column); var bottomY = continentLand.Max(x => x.Row); var rightX = continentLand.Max(x => x.Column); // Squares count in height for one square in width var ratioHeightWidth = (int)Math.Round((bottomY - topY + 1) / (double)(rightX - leftX + 1)); foreach (var chunkType in chunksByType.Keys) { chunksByType[chunkType].AddRange(FiilContinentBlueprintWithBiomeChunks( chunksCountByType[chunkType], chunkType.SizeInt * CHUNK_SIZE_RATIO, topY, leftX, bottomY, rightX, ratioHeightWidth, chunkType.Temperatures)); } // Rivers count on the continent. var riversCount = (int)Math.Round(continentLand.Count * BiomePivot.River.AppearanceRate); for (int i = 0; i < riversCount; i++) { var river = new List <Tuple <int, int> >(); // Random river starting point. var riverPt = new Tuple <int, int>( Tools.Randomizer.Next(topY, bottomY), Tools.Randomizer.Next(leftX, rightX) ); // The river can go in two directions [(bottom or top) and (left or right)] var forbiddenDirection1 = (DirectionPivot)Tools.Randomizer.Next(2, 4); var forbiddenDirection2 = (DirectionPivot)Tools.Randomizer.Next(0, 2); // Loops until the river reachs the coast, or another river. while (riverPt.Item1 >= topY && riverPt.Item1 <= bottomY && riverPt.Item2 >= leftX && riverPt.Item2 <= rightX && !rivers.Any(r => r.Any(rsquare => rsquare.Item1 == riverPt.Item1 && rsquare.Item2 == riverPt.Item2))) { river.Add(riverPt); DirectionPivot currentDirection; do { // Picks a random direction, which can't be a forbidden one. currentDirection = (DirectionPivot)Tools.Randomizer.Next(0, 4); }while (currentDirection == forbiddenDirection1 || currentDirection == forbiddenDirection2); riverPt = new Tuple <int, int>( riverPt.Item1 + (currentDirection == DirectionPivot.Bottom ? 1 : (currentDirection == DirectionPivot.Top ? -1 : 0)), riverPt.Item2 + (currentDirection == DirectionPivot.Right ? 1 : (currentDirection == DirectionPivot.Left ? -1 : 0)) ); } rivers.Add(river); } // Huts count on the continent. var hutsCount = (int)Math.Round(continentLand.Count * HUT_APPEARANCE_RATE); // Creates hut locations. for (int i = 0; i < hutsCount; i++) { Tuple <int, int> hutPoint; do { hutPoint = new Tuple <int, int>( Tools.Randomizer.Next(topY, bottomY), Tools.Randomizer.Next(leftX, rightX) ); }while (huts.Any(h => h.Item1 == hutPoint.Item1 && h.Item2 == hutPoint.Item2)); huts.Add(hutPoint); } } foreach (var type in chunksByType.Keys) { foreach (var chunkOfType in chunksByType[type]) { foreach (var ofType in chunkOfType) { var currSq = _mapSquareList[ofType.Item1, ofType.Item2]; currSq.ChangeBiome(type); } } } // Overrides chunks with river squares. rivers.ForEach(r => r.ForEach(rSquare => _mapSquareList[rSquare.Item1, rSquare.Item2].ChangeBiome(BiomePivot.River))); // Add huts. foreach (var hSquare in huts) { HutPivot hut = null; var location = _mapSquareList[hSquare.Item1, hSquare.Item2]; var typeHut = Tools.Randomizer.Next(0, 6); switch (typeHut) { case 0: hut = HutPivot.EmptyHut(location); break; case 1: hut = HutPivot.AdvanceHut(location); break; case 2: hut = HutPivot.BarbariansHut(location); break; case 3: hut = HutPivot.SettlerHut(location); break; case 4: hut = HutPivot.FriendlyCavalryUnitHut(location); break; case 5: hut = HutPivot.GoldHut(location); break; } if (hut != null) { _huts.Add(hut); } } }
/// <summary> /// Computes the number of <see cref="MapSquarePivot"/> for a chunk of the current biome, in the specified context. /// </summary> /// <param name="totalSquaresCount">Total count of squares in the continent.</param> /// <param name="chunkCoeff">Number real of squares in a <see cref="BiomeSizePivot.Small"/> chunk.</param> /// <param name="humidity">Level of <see cref="HumidityPivot"/> at the current latitude.</param> /// <param name="age">Age of the map.</param> /// <returns>Number of squares </returns> internal int ChunkSquaresCount(int totalSquaresCount, double chunkCoeff, HumidityPivot humidity, AgePivot age) { if (age == AgePivot.New) { if (Age == AgePivot.Old) { chunkCoeff += 1.5; } else if (Age == AgePivot.New) { chunkCoeff -= 1.5; } } else if (age == AgePivot.Old) { if (Age == AgePivot.Old) { chunkCoeff -= 1.5; } else if (Age == AgePivot.New) { chunkCoeff += 1.5; } } var realRatio = AppearanceRate; if (humidity == HumidityPivot.Dry) { if (Humidity == HumidityPivot.Dry) { realRatio *= 2; } else if (Humidity == HumidityPivot.Wet) { realRatio /= 2; } } else if (humidity == HumidityPivot.Wet) { if (Humidity == HumidityPivot.Dry) { realRatio /= 2; } else if (Humidity == HumidityPivot.Wet) { realRatio *= 2; } } return((int)Math.Round((totalSquaresCount * (realRatio * 3)) / ((int)Size * chunkCoeff))); }