public void ComputeWarpPointConnectivity() { warpGraph = new ConnectivityGraph <ObjectLocation <StarSystem> >(Galaxy.Current.StarSystemLocations); foreach (var ssl in warpGraph) { foreach (var wp in ssl.Item.FindSpaceObjects <WarpPoint>()) { if (wp.TargetStarSystemLocation == null) { continue; // can't make connection if we don't know where warp point ends! } warpGraph.Connect(ssl, wp.TargetStarSystemLocation); } } }
// TODO - status messages for the GUI private void PlaceEmpire(Galaxy gal, Empire emp, PRNG dice) { if (AllSystemsExplored) { // set all systems explored foreach (var sys in gal.StarSystemLocations.Select(ssl => ssl.Item)) { sys.ExploredByEmpires.Add(emp); } } // give empire starting techs Galaxy.Current.CleanGameState(); // need to know what the techs in the game are! foreach (var tech in Mod.Current.Technologies.Where(t => !t.IsRacial || emp.Abilities().Any(a => a.Rule.Matches("Tech Area") && a.Value1 == t.RacialTechID))) { switch (StartingTechnologyLevel) { case StartingTechnologyLevel.Low: emp.ResearchedTechnologies[tech] = tech.StartLevel; break; case StartingTechnologyLevel.Medium: emp.ResearchedTechnologies[tech] = Math.Max(tech.StartLevel, tech.RaiseLevel); break; case StartingTechnologyLevel.High: emp.ResearchedTechnologies[tech] = tech.MaximumLevel; break; } } // give empire starting resources and storage capacity foreach (var r in Resource.All.Where(r => r.IsGlobal)) { emp.StoredResources.Add(r, StartingResources); emp.IntrinsicResourceStorage.Add(r, ResourceStorage); } // give empire starting research emp.BonusResearch = StartingResearch + (int)(ResearchPointsPerUnspentEmpirePoint * (EmpirePoints - emp.PrimaryRace.Traits.Sum(q => q.Cost))); // TODO - moddable colony techs? string colonyTechName = null; if ((emp.PrimaryRace.NativeSurface) == "Rock") { colonyTechName = "Rock Planet Colonization"; } else if ((emp.PrimaryRace.NativeSurface) == "Ice") { colonyTechName = "Ice Planet Colonization"; } else if ((emp.PrimaryRace.NativeSurface) == "Gas Giant") { colonyTechName = "Gas Giant Colonization"; } var colonyTech = Mod.Current.Technologies.SingleOrDefault(t => t.Name == colonyTechName); if (colonyTech != null && emp.ResearchedTechnologies[colonyTech] < 1) { emp.ResearchedTechnologies[colonyTech] = 1; } // find facilities to place on homeworlds var facils = emp.UnlockedItems.OfType <FacilityTemplate>(); var sy = facils.WithMax(facil => facil.GetAbilityValue("Space Yard", 2).ToInt()).LastOrDefault(); var sp = facils.LastOrDefault(facil => facil.HasAbility("Spaceport")); var rd = facils.LastOrDefault(facil => facil.HasAbility("Supply Generation")); var min = facils.WithMax(facil => facil.GetAbilityValue("Resource Generation - Minerals").ToInt()).LastOrDefault(); var org = facils.WithMax(facil => facil.GetAbilityValue("Resource Generation - Organics").ToInt()).LastOrDefault(); var rad = facils.WithMax(facil => facil.GetAbilityValue("Resource Generation - Radioactives").ToInt()).LastOrDefault(); var res = facils.WithMax(facil => facil.GetAbilityValue("Point Generation - Research").ToInt()).LastOrDefault(); // TODO - game setup option for intel facilities on homeworlds? HomeworldStartingFacilities.txt ala se5? // SY rate, for colonies var rate = new ResourceQuantity(); if (sy != null) { // TODO - define mappings between SY ability numbers and resource names in a mod file rate.Add(Resource.Minerals, sy.GetAbilityValue("Space Yard", 2, true, true, a => a.Value1 == "1").ToInt()); rate.Add(Resource.Organics, sy.GetAbilityValue("Space Yard", 2, true, true, a => a.Value1 == "2").ToInt()); rate.Add(Resource.Radioactives, sy.GetAbilityValue("Space Yard", 2, true, true, a => a.Value1 == "3").ToInt()); } // build connectivity graph for computing warp distance var graph = new ConnectivityGraph <StarSystem>(); foreach (var s in Galaxy.Current.StarSystemLocations.Select(ssl => ssl.Item)) { graph.Add(s); } foreach (var s in Galaxy.Current.StarSystemLocations.Select(ssl => ssl.Item)) { foreach (var wp in s.FindSpaceObjects <WarpPoint>()) { graph.Connect(s, wp.TargetStarSystemLocation.Item, true); } } for (int i = 0; i < HomeworldsPerEmpire; i++) { // TODO - respect Empire Placement and Max Homeworld Dispersion settings var planets = gal.StarSystemLocations.SelectMany(ssl => ssl.Item.FindSpaceObjects <Planet>(p => p.Owner == null && p.MoonOf == null)); var okSystems = gal.StarSystemLocations.Select(ssl => ssl.Item).Where(sys => sys.EmpiresCanStartIn); if (i > 0) { // make sure subsequent homeworlds are placed within a limited number of warps from the first homeworld okSystems = okSystems.Where(sys => graph.ComputeDistance(sys, emp.OwnedSpaceObjects.OfType <Planet>().First().FindStarSystem()) <= MaxHomeworldDispersion); } switch (EmpirePlacement) { case EmpirePlacement.CanStartInSameSystem: // no further filtering break; case EmpirePlacement.DifferentSystems: // filter to systems containing no other empires' homeworlds okSystems = okSystems.Where(sys => !sys.FindSpaceObjects <Planet>(p => p.Owner != null && p.Owner != emp).Any()); break; case EmpirePlacement.Equidistant: // filter to systems containing no other empires' homeworlds okSystems = okSystems.Where(sys => !sys.FindSpaceObjects <Planet>(p => p.Owner != null && p.Owner != emp).Any()); // filter to systems that are the maximum distance away from any other empire's homeworlds var otherEmpireHomeSystems = gal.StarSystemLocations.SelectMany(ssl => ssl.Item.FindSpaceObjects <Planet>(p => p.Owner != null && p.Owner != emp).Select(p => p.FindStarSystem()).Distinct()).ToArray(); okSystems = okSystems.WithMax(sys => otherEmpireHomeSystems.Min(o => graph.ComputeDistance(sys, o))); break; } okSystems = okSystems.ToArray(); if (!okSystems.Any()) { // replace an inhospitable system with a hospitable one var convertSys = gal.StarSystemLocations.Select(ssl => ssl.Item).Where(sys => !sys.EmpiresCanStartIn).PickRandom(dice); if (convertSys == null) { throw new Exception("No suitable system found to place " + emp + "'s homeworld #" + (i + 1) + ". (Try increasing the number of star systems.)"); } var newSys = Mod.Current.StarSystemTemplates.Where(q => q.EmpiresCanStartIn).PickRandom(dice).Instantiate(); var sid = convertSys.ID; newSys.CopyTo(convertSys); convertSys.ID = sid; convertSys.Name = Mod.Current.StarSystemNames.Except(gal.StarSystemLocations.Select(q => q.Item.Name)).PickRandom(dice); foreach (var l in Galaxy.Current.StarSystemLocations) { foreach (var wp in l.Item.FindSpaceObjects <WarpPoint>().Where(q => q.Target.StarSystem == convertSys).ToArray()) { wp.Dispose(); WarpPointPlacementStrategy.PlaceWarpPoints(Galaxy.Current.StarSystemLocations.Single(q => q.Item == convertSys), l); } } GalaxyTemplate.NameStellarObjects(convertSys); okSystems = new[] { convertSys }; } Planet hw; planets = planets.Where(p => okSystems.Contains(p.FindStarSystem())); if (!planets.Any()) { // make sure we're placing the homeworld in a system with at least one empty sector okSystems = okSystems.Where(sys2 => sys2.Sectors.Any(sec => !sec.SpaceObjects.Any())); if (!okSystems.Any()) { throw new Exception("No suitable system found to place " + emp + "'s homeworld #" + (i + 1) + ". (Try regenerating the map or increasing the number of star systems.)"); } // make brand new planet in an OK system var sys = okSystems.PickRandom(dice); var nextNum = sys.FindSpaceObjects <Planet>(p => p.MoonOf == null).Count() + 1; hw = MakeHomeworld(emp, sys.Name + " " + nextNum.ToRomanNumeral(), dice); var okSectors = sys.Sectors.Where(sector => !sector.SpaceObjects.Any()); okSectors.PickRandom(dice).Place(hw); } else { hw = planets.PickRandom(dice); } if (hw.Surface != emp.PrimaryRace.NativeSurface || hw.Atmosphere != emp.PrimaryRace.NativeAtmosphere || hw.Size != HomeworldSize) { var replacementHomeworld = MakeHomeworld(emp, hw.Name, dice); replacementHomeworld.CopyTo(hw); } hw.ResourceValue[Resource.Minerals] = hw.ResourceValue[Resource.Organics] = hw.ResourceValue[Resource.Radioactives] = HomeworldValue; hw.Colony = new Colony { Owner = emp, ConstructionQueue = new ConstructionQueue(hw), IsHomeworld = true, }; hw.AddPopulation(emp.PrimaryRace, hw.Size.MaxPopulation); if (sy != null && hw.Colony.Facilities.Count < hw.MaxFacilities) { hw.Colony.Facilities.Add(sy.Instantiate()); } if (sp != null && hw.Colony.Facilities.Count < hw.MaxFacilities && (!emp.HasAbility("No Spaceports") || sp.Abilities.Count > 1)) { // natural merchants get spaceports only if spaceports have more than one ability // of course, if the other abilities are *penalties*... oh well, they can scrap them! hw.Colony.Facilities.Add(sp.Instantiate()); } if (rd != null && hw.Colony.Facilities.Count < hw.MaxFacilities) { hw.Colony.Facilities.Add(rd.Instantiate()); } var lastCount = 0; while (hw.Colony.Facilities.Count < hw.MaxFacilities && hw.Colony.Facilities.Count > lastCount) { lastCount = hw.Colony.Facilities.Count; if (min != null && hw.Colony.Facilities.Count < hw.MaxFacilities) { hw.Colony.Facilities.Add(min.Instantiate()); } if (org != null && hw.Colony.Facilities.Count < hw.MaxFacilities) { hw.Colony.Facilities.Add(org.Instantiate()); } if (rad != null && hw.Colony.Facilities.Count < hw.MaxFacilities) { hw.Colony.Facilities.Add(rad.Instantiate()); } // no research facilities needed at max tech! if (StartingTechnologyLevel != StartingTechnologyLevel.High) { if (res != null && hw.Colony.Facilities.Count < hw.MaxFacilities) { hw.Colony.Facilities.Add(res.Instantiate()); } } } foreach (var f in hw.Colony.Facilities) { f.ConstructionProgress = f.Cost; } } // mark home systems explored foreach (var sys in gal.StarSystemLocations.Select(ssl => ssl.Item)) { if (!sys.ExploredByEmpires.Contains(emp) && sys.FindSpaceObjects <Planet>().Any(planet => planet.Owner == emp)) { sys.ExploredByEmpires.Add(emp); } } // in case two empires started in the same system foreach (var x in gal.FindSpaceObjects <ISpaceObject>().Owned().ToArray()) { x.UpdateEmpireMemories(); } }
/// <param name="status">A status object to report status back to the GUI.</param> /// <param name="desiredProgress">How much progress should we report back to the GUI when we're done initializing the galaxy? 1.0 means all done with everything that needs to be done.</param> public Galaxy Instantiate(Status status, double desiredProgress, PRNG dice) { var gal = new Galaxy(); gal.Width = GameSetup.GalaxySize.Width; gal.Height = GameSetup.GalaxySize.Height; gal.MinPlanetValue = GameSetup.MinPlanetValue; gal.MinSpawnedPlanetValue = GameSetup.MinSpawnedPlanetValue; gal.MaxSpawnedPlanetValue = GameSetup.MaxSpawnedPlanetValue; gal.MaxPlanetValue = GameSetup.MaxPlanetValue; gal.MinAsteroidValue = GameSetup.MinAsteroidValue; gal.MinSpawnedAsteroidValue = GameSetup.MinSpawnedAsteroidValue; gal.MaxSpawnedAsteroidValue = GameSetup.MaxSpawnedAsteroidValue; gal.EventFrequency = GameSetup.EventFrequency; gal.MaximumEventSeverity = GameSetup.MaximumEventSeverity; var bounds = new Rectangle(-GameSetup.GalaxySize.Width / 2, -GameSetup.GalaxySize.Height / 2, GameSetup.GalaxySize.Width, GameSetup.GalaxySize.Height); var unusedNames = new List <string>(Mod.Current.StarSystemNames); // create star systems if (status != null) { status.Message = "Creating star systems"; } var progressPerStarSystem = (desiredProgress - (status == null ? 0 : status.Progress)) / GameSetup.StarSystemCount / 2d; for (int i = 0; i < GameSetup.StarSystemCount; i++) { if (status != null) { status.Message = "Creating star system " + (i + 1) + " of " + GameSetup.StarSystemCount; } var p = StarSystemPlacementStrategy.PlaceStarSystem(gal, MinimumStarSystemDistance, bounds, GameSetup.StarSystemCount - i, dice); if (p == null) { break; // no more locations available } var sst = StarSystemTemplateChances.PickWeighted(dice); sst.Dice = dice; var sys = sst.Instantiate(); sys.Name = unusedNames.PickRandom(dice); unusedNames.Remove(sys.Name); NameStellarObjects(sys); gal.StarSystemLocations.Add(new ObjectLocation <StarSystem> { Location = p.Value, Item = sys }); if (status != null) { status.Progress += progressPerStarSystem; } } var progressPerWarp = (desiredProgress - (status == null ? 0 : status.Progress)) / (gal.StarSystemLocations.Count * 2); // create warp points if (status != null) { status.Message = "Creating warp points"; } var graph = new ConnectivityGraph <ObjectLocation <StarSystem> >(); foreach (var ssl in gal.StarSystemLocations) { graph.Add(ssl); } int wpsGenerated = 0; while (wpsGenerated < gal.StarSystemLocations.Count * 2) { // pick 2 systems ObjectLocation <StarSystem> startLocation = null, endLocation = null; (startLocation, endLocation) = MinDistanceDisconnectedSystemPair(graph); // create the warp points if (startLocation != null && endLocation != null) { GameSetup.WarpPointPlacementStrategy.PlaceWarpPoints(startLocation, endLocation); // mark systems connected graph.Connect(startLocation, endLocation, true); wpsGenerated++; } else { break; } if (status != null) { status.Progress += progressPerWarp; } } // TODO - delete excess warp points if system groups count is >1 if (status != null) { status.Progress = desiredProgress; } return(gal); }