public void WarpPointAngularDistance() { Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(15, 0, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(-15, 0, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(345, 0, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(90, 0, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(-90, 0, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(270, 0, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(165, 180, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(-195, 180, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(90, 180, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(-90, 180, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(270, 180, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(0, 30, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(15, 30, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(-15, 30, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(345, 30, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(90, 30, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(-30, 30, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(330, 30, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(0, -30, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(15, -30, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(-15, -30, 60)); Assert.IsTrue(GalaxyTemplate.AngleIsInRangeExclusive(345, -30, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(90, -30, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(-90, -30, 60)); Assert.IsFalse(GalaxyTemplate.AngleIsInRangeExclusive(270, -30, 60)); }
public void VerticalAndHorizontalIntersectionsCount() { var p1 = new Point(-1, 0); var p2 = new Point(1, 0); var q1 = new Point(0, -1); var q2 = new Point(0, 1); Assert.IsTrue(GalaxyTemplate.IntersectsExceptAtEnds(p1, p2, q1, q2)); }
public void CollinearIntersectionsCount() { var p1 = new Point(0, 0); var p2 = new Point(0, 10); var q1 = new Point(0, 2); var q2 = new Point(0, 11); Assert.IsTrue(GalaxyTemplate.IntersectsExceptAtEnds(p1, p2, q1, q2)); }
public void CrossoverIntersectionsCount() { var p1 = new Point(-1, -1); var p2 = new Point(1, 1); var q1 = new Point(1, -1); var q2 = new Point(-1, 1); Assert.IsTrue(GalaxyTemplate.IntersectsExceptAtEnds(p1, p2, q1, q2)); }
public void IntersectionsAtEndpointAndMiddleDoCount() { var p1 = new Point(0, 0); var p2 = new Point(10, 0); var q1 = new Point(9, -1); var q2 = new Point(11, 1); Assert.IsTrue(GalaxyTemplate.IntersectsExceptAtEnds(p1, p2, q1, q2)); }
public void IntersectionsAtEndpointsDoNotCount() { var p1 = new Point(0, 0); var p2 = new Point(10, 0); var q1 = new Point(10, 0); var q2 = new Point(11, 1); Assert.IsFalse(GalaxyTemplate.IntersectsExceptAtEnds(p1, p2, q1, q2)); }
// 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(); } }
public override IEnumerable <IModObject> Load(Mod mod) { foreach (var rec in DataFile.Records) { var galtemp = new GalaxyTemplate(); galtemp.TemplateParameters = rec.Parameters; string temp; int index = -1; galtemp.ModID = rec.Get <string>("ID", galtemp); rec.TryFindFieldValue("Name", out temp, ref index, Mod.Errors, 0, true); galtemp.Name = temp; mod.GalaxyTemplates.Add(galtemp); rec.TryFindFieldValue("Description", out temp, ref index, Mod.Errors, 0, true); galtemp.Description = temp; rec.TryFindFieldValue("Min Dist Between Systems", out temp, ref index, Mod.Errors, 0, true); int mindist; if (!int.TryParse(temp, out mindist)) { Mod.Errors.Add(new DataParsingException("Cannot find field \"Min Dist Between Systems\"", Mod.CurrentFileName, rec)); } galtemp.MinimumStarSystemDistance = mindist; rec.TryFindFieldValue("System Placement", out temp, ref index, Mod.Errors, 0, true); if (temp == "Random") { galtemp.StarSystemPlacementStrategy = new RandomStarSystemPlacementStrategy(); } else if (temp == "Clusters") { galtemp.StarSystemPlacementStrategy = new ClusteredStarSystemPlacementStrategy(); } else if (temp == "Spiral") { galtemp.StarSystemPlacementStrategy = new SpiralStarSystemPlacementStrategy(); } else if (temp == "Diffuse") { galtemp.StarSystemPlacementStrategy = new DiffuseStarSystemPlacementStrategy(); } else if (temp == "Grid") { galtemp.StarSystemPlacementStrategy = new GridStarSystemPlacementStrategy(); } else { Mod.Errors.Add(new DataParsingException("Invalid value \"" + temp + "\" for field \"System Placement\". Must be Random, Clusters, Spiral, Diffuse, or Grid.", Mod.CurrentFileName, rec)); galtemp.StarSystemPlacementStrategy = new RandomStarSystemPlacementStrategy(); // default } rec.TryFindFieldValue("Max Warp Points per Sys", out temp, ref index, Mod.Errors, 0, true); int maxwarp; if (!int.TryParse(temp, out maxwarp)) { Mod.Errors.Add(new DataParsingException("Cannot find field \"Max Warp Points per Sys\"", Mod.CurrentFileName, rec)); } galtemp.MaxWarpPointsPerSystem = maxwarp; rec.TryFindFieldValue("Min Angle Between WP", out temp, ref index, Mod.Errors, 0, true); int minangle; if (!int.TryParse(temp, out minangle)) { Mod.Errors.Add(new DataParsingException("Cannot find field \"Min Angle Between WP\"", Mod.CurrentFileName, rec)); } galtemp.MinWarpPointAngle = minangle; int count = 1; int start = 0; while (true) { StarSystemTemplate sst; int chance; if (!rec.TryFindFieldValue(new string[] { "Type " + count + " Name", "Type Name" }, out temp, ref start, null, start, true)) { break; // couldn't load next chance } else { sst = mod.StarSystemTemplates.FindByName(temp); if (sst == null) { Mod.Errors.Add(new DataParsingException("Could not find star system template \"" + temp + "\".", Mod.CurrentFileName, rec, null)); continue; // skip this chance } } start++; if (!rec.TryFindFieldValue(new string[] { "Type " + count + " Chance", "Type Chance" }, out temp, ref start, null, start)) { break; // couldn't load next chance } else { if (!int.TryParse(temp, out chance)) { Mod.Errors.Add(new DataParsingException("Type Chance field value must be an integer.", Mod.CurrentFileName, rec, null)); } } start++; // silly Adamant Mod refers to the same star system type twice... if (galtemp.StarSystemTemplateChances.ContainsKey(sst)) { galtemp.StarSystemTemplateChances[sst] += chance; } else { galtemp.StarSystemTemplateChances.Add(sst, chance); } count++; } yield return(galtemp); } }