Example #1
0
        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);
                }
            }
        }
Example #2
0
        // 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();
            }
        }
Example #3
0
        /// <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);
        }