Пример #1
0
 public DistanceConstraint(string[] args, IZoneResolver zoneResolver)
 {
     if (args.Length == 3)
     {
         _targetZone = zoneResolver.ResolveZone(args[0].Trim());
         if (!int.TryParse(args[2], out var v))
         {
             _test = _ => false;
         }
         else
         {
             var trimmed = args[1].Trim();
             _test = trimmed switch
             {
                 "<" => i => i <v,
                                ">" => i => i> v,
                 "=" => i => i == v,
                 _ => _ => false
             };
         }
     }
     else
     {
         _test = _ => false;
     }
 }
Пример #2
0
 public HashSet <GalaxyZone> ConnectedRegion(
     GalaxyZone v,
     GalaxyZone ignoreZone,
     int maxDistance = int.MaxValue)
 {
     return(ConnectedRegion(v, x => x.Item2 != ignoreZone, maxDistance));
 }
Пример #3
0
    public Dictionary <GalaxyZone, int> ConnectedRegionDistance(GalaxyZone v)
    {
        var members = new Dictionary <GalaxyZone, int> {
            { v, 0 }
        };
        int cost = 1;

        while (true)
        {
            var lastCount = members.Count;
            // For each member, add all vertices that are connected to it but are not already a member
            // Also, if there is a zone being ignored, do not traverse across it
            foreach (var member in members.Keys.ToArray())
            {
                foreach (var adjacentZone in member.AdjacentZones)
                {
                    if (!members.ContainsKey(adjacentZone))
                    {
                        members.Add(adjacentZone, cost);
                    }
                }
            }
            // If we have stopped finding neighbors, stop traversing
            if (members.Count == lastCount)
            {
                return(members);
            }
            cost++;
        }
    }
Пример #4
0
 public HashSet <GalaxyZone> ConnectedRegion(
     GalaxyZone v,
     GalaxyZone ignoreLinkSource,
     GalaxyZone ignoreLinkTarget,
     int maxDistance = int.MaxValue)
 {
     return(ConnectedRegion(v, x => x.Item1 != ignoreLinkSource || x.Item2 != ignoreLinkTarget, maxDistance));
 }
Пример #5
0
 public LoadoutGenerator(
     ref Random random,
     ItemManager itemManager,
     Galaxy galaxy,
     GalaxyZone zone,
     Faction faction,
     float priceExponent)
 {
     Random        = random;
     ItemManager   = itemManager;
     Galaxy        = galaxy;
     Zone          = zone;
     Faction       = faction;
     PriceExponent = priceExponent;
 }
Пример #6
0
    public static ZonePack GenerateZone(
        ItemManager itemManager,
        ZoneGenerationSettings zoneSettings,
        Galaxy galaxy,
        GalaxyZone galaxyZone,
        bool isTutorial = false)
    {
        var pack = new ZonePack();

        var random = new Random(unchecked ((uint)galaxyZone.Name.GetHashCode()) ^ hash(galaxyZone.Position));

        var density = saturate(galaxy.Background.CloudDensity(galaxyZone.Position) / 2);

        pack.Radius = zoneSettings.ZoneRadius.Evaluate(density);
        pack.Mass   = zoneSettings.ZoneMass.Evaluate(density);
        var targetSubzoneCount = zoneSettings.SubZoneCount.Evaluate(density);

        //Debug.Log($"Generating zone at position {zone.Position} with radius {zoneRadius} and mass {zoneMass}");

        var planets = new List <GeneratorPlanet>();

        if (targetSubzoneCount > 1)
        {
            var zoneBoundary = new Circle(float2.zero, pack.Radius * zoneSettings.ZoneBoundaryRadius);
            float boundaryTangentRadius(float2 point) => - zoneBoundary.DistanceTo(point);

            var occupiedAreas = new List <Circle>();
            float tangentRadius(float2 point) => min(boundaryTangentRadius(point), occupiedAreas.Min(circle => circle.DistanceTo(point)));

            var startPosition = random.NextFloat(pack.Radius * .25f, pack.Radius * .5f) * random.NextFloat2Direction();
            occupiedAreas.Add(new Circle(startPosition, boundaryTangentRadius(startPosition)));

            int samples = 0;
            while (occupiedAreas.Count < targetSubzoneCount && samples < MaximumPlacementSamples)
            {
                samples = 0;
                for (int i = 0; i < MaximumPlacementSamples; i++)
                {
                    var samplePos = random.NextFloat2(-pack.Radius, pack.Radius);
                    var rad       = tangentRadius(samplePos);
                    if (rad > 0)
                    {
                        occupiedAreas.Add(new Circle(samplePos, rad));
                        break;
                    }

                    samples++;
                }
            }

            var totalArea = occupiedAreas.Sum(c => c.Area);
            foreach (var c in occupiedAreas)
            {
                planets.AddRange(GenerateEntities(zoneSettings, ref random, c.Area / totalArea * pack.Mass, c.Radius, c.Center));
            }
        }
        else
        {
            planets.AddRange(GenerateEntities(zoneSettings, ref random, pack.Mass, pack.Radius, float2.zero));
        }

        // Create collections to map between zone generator output and database entries
        var orbitMap        = new Dictionary <GeneratorPlanet, OrbitData>();
        var orbitInverseMap = new Dictionary <OrbitData, GeneratorPlanet>();

        // Create orbit database entries
        pack.Orbits = planets.Select(planet =>
        {
            var data = new OrbitData
            {
                FixedPosition = planet.FixedPosition,
                Distance      = new ReactiveProperty <float>(planet.Distance),
                //Period = planet.Period,
                Phase = planet.Phase
            };
            orbitMap[planet]      = data;
            orbitInverseMap[data] = planet;
            return(data);
        }).ToList();

        // Link OrbitData parents to database GUIDs
        foreach (var data in pack.Orbits)
        {
            data.Parent = orbitInverseMap[data].Parent != null
                ? orbitMap[orbitInverseMap[data].Parent].ID
                : Guid.Empty;
        }

        // Cache resource densities
        // var resourceMaps = mapLayers.Values
        //  .ToDictionary(m => m.ID, m => m.Evaluate(zone.Position, settings.ShapeSettings));

        pack.Planets = planets.Where(p => !p.Empty).Select(planet =>
        {
            // Dictionary<Guid, float> planetResources = new Dictionary<Guid, float>();
            BodyType bodyType = planet.Belt ? BodyType.Asteroid :
                                planet.Mass > zoneSettings.SunMass ? BodyType.Sun :
                                planet.Mass > zoneSettings.GasGiantMass ? BodyType.GasGiant :
                                planet.Mass > zoneSettings.PlanetMass ? BodyType.Planet : BodyType.Planetoid;

            // foreach (var r in resources)
            // {
            //  if ((bodyType & r.ResourceBodyType) != 0)
            //  {
            //   float quantity = ResourceValue(ref random, settings, r, r.ResourceDensity.Aggregate(1f, (m, rdm) => m * resourceMaps[rdm]));
            //   if (r.Floor < quantity) planetResources.Add(r.ID, quantity);
            //  }
            // }

            BodyData planetData;
            switch (bodyType)
            {
            case BodyType.Asteroid:
                planetData = new AsteroidBeltData();
                break;

            case BodyType.Planetoid:
            case BodyType.Planet:
                planetData = new PlanetData();
                break;

            case BodyType.GasGiant:
                planetData = new GasGiantData();
                break;

            case BodyType.Sun:
                planetData = new SunData();
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            planetData.Mass.Value = planet.Mass;
            planetData.Orbit      = orbitMap[planet].ID;
            // planetData.Resources = planetResources;
            planetData.Name.Value = planetData.ID.ToString().Substring(0, 8);
            if (planetData is AsteroidBeltData beltData)
            {
                beltData.Asteroids =
                    Enumerable.Range(0, (int)(zoneSettings.AsteroidCount.Evaluate(beltData.Mass.Value * orbitMap[planet].Distance.Value)))
                    .Select(_ => new Asteroid
                {
                    Distance      = orbitMap[planet].Distance.Value + random.NextFloat() * (random.NextFloat() - .5f) * zoneSettings.AsteroidBeltWidth.Evaluate(orbitMap[planet].Distance.Value),
                    Phase         = random.NextFloat(),
                    Size          = random.NextFloat(),
                    RotationSpeed = zoneSettings.AsteroidRotationSpeed.Evaluate(random.NextFloat())
                })
                    //.OrderByDescending(a=>a.Size)
                    .ToArray();
            }
            else if (planetData is GasGiantData gas)
            {
                if (gas is SunData sun)
                {
                    float primary    = random.NextFloat();
                    float secondary  = frac(primary + 1 + zoneSettings.SunSecondaryColorDistance * (random.NextFloat() > .5 ? 1 : -1));
                    gas.Colors.Value = new []
                    {
                        float4(ColorMath.HsvToRgb(float3(primary, zoneSettings.SunColorSaturation, .5f)), 0),
                        float4(ColorMath.HsvToRgb(float3(secondary, zoneSettings.SunColorSaturation, 1)), 1)
                    };
                    sun.FogTintColor.Value = ColorMath.HsvToRgb(float3(primary, zoneSettings.SunFogTintSaturation, 1));
                    sun.LightColor.Value   = ColorMath.HsvToRgb(float3(primary, zoneSettings.SunLightSaturation, 1));
                    gas.FirstOffsetDomainRotationSpeed.Value = 5;
                }
                else
                {
                    // Define primary color and two adjacent colors
                    float primary = random.NextFloat();
                    float right   = frac(primary + zoneSettings.GasGiantBandColorSeparation);
                    float left    = frac(primary + 1 - zoneSettings.GasGiantBandColorSeparation);

                    // Create n time keys from 0 to 1
                    var bandCount = (int)(zoneSettings.GasGiantBandCount.Evaluate(random.NextFloat()) + .5f);
                    var times     = Enumerable.Range(0, bandCount)
                                    .Select(i => (float)i / (bandCount - 1));

                    // Each band has a chance of being either the primary or one of the adjacent hues
                    // Saturation and Value are random with curves applied
                    gas.Colors.Value = times
                                       .Select(time => float4(ColorMath.HsvToRgb(float3(
                                                                                     random.NextFloat() > zoneSettings.GasGiantBandAltColorChance ? primary : (random.NextFloat() > .5f ? right : left),
                                                                                     zoneSettings.GasGiantBandSaturation.Evaluate(random.NextFloat()),
                                                                                     zoneSettings.GasGiantBandSaturation.Evaluate(random.NextFloat()))), time))
                                       .ToArray();

                    gas.FirstOffsetDomainRotationSpeed.Value = 0;
                }
                gas.AlbedoRotationSpeed.Value             = -3;
                gas.FirstOffsetRotationSpeed.Value        = 5;
                gas.SecondOffsetRotationSpeed.Value       = 10;
                gas.SecondOffsetDomainRotationSpeed.Value = -25;
            }
            return(planetData);
        }).ToList();

        var nearestFaction         = galaxy.Factions.MinBy(f => galaxy.HomeZones[f].Distance[galaxyZone]);
        var nearestFactionHomeZone = galaxy.HomeZones[nearestFaction];
        var factionPresence        = nearestFaction.InfluenceDistance - nearestFactionHomeZone.Distance[galaxyZone] + 1;

        var storyStations           = galaxyZone.Locations.Where(story => story.Type == LocationType.Station).ToArray();
        var stationCount            = (int)(random.NextFloat() * (factionPresence + 1)) + storyStations.Length;
        var potentialLagrangePoints = planets
                                      .Where(p => p.Parent != null && p.Parent.Children
                                             .TrueForAll(c => !(c != p && abs(c.Distance - p.Distance) < .1f))) // Filter Rosettes
                                      .OrderBy(p => p.Distance)
                                      .ToArray();
        // Pick a selection from the middle of the distribution
        var selectedStationOrbits = potentialLagrangePoints
                                    .Skip(potentialLagrangePoints.Length / 2)
                                    .Take(stationCount)
                                    .Select(p => orbitMap[p])
                                    .ToArray();

        var loadoutGenerators = new Dictionary <Faction, LoadoutGenerator>();

        LoadoutGenerator GetLoadoutGenerator(Faction faction)
        {
            if (!loadoutGenerators.ContainsKey(faction))
            {
                loadoutGenerators[faction] = isTutorial
                                ? new LoadoutGenerator(ref random, itemManager, faction, .5f)
                                : new LoadoutGenerator(ref random, itemManager, galaxy, galaxyZone, faction, .5f);
            }
            return(loadoutGenerators[faction]);
        }

        OrbitData CreateLagrangeOrbit(OrbitData baseOrbit)
        {
            var lagrangeOrbit = new OrbitData
            {
                ID       = Guid.NewGuid(),
                Parent   = baseOrbit.Parent,
                Distance = new ReactiveProperty <float>(baseOrbit.Distance.Value),
                Phase    = baseOrbit.Phase + PI / 3 * sign(random.NextFloat() - .5f)
            };

            pack.Orbits.Add(lagrangeOrbit);
            return(lagrangeOrbit);
        }

        void PlaceTurret(OrbitData orbit, LoadoutGenerator loadoutGenerator, int distanceMultiplier)
        {
            var phase = 20f * distanceMultiplier / orbit.Distance.Value;

            var turretOrbit = new OrbitData
            {
                ID       = Guid.NewGuid(),
                Parent   = orbit.Parent,
                Distance = new ReactiveProperty <float>(orbit.Distance.Value),
                Phase    = orbit.Phase + phase
            };

            pack.Orbits.Add(turretOrbit);
            var turret = loadoutGenerator.GenerateTurretLoadout();

            turret.Orbit = turretOrbit.ID;
            pack.Entities.Add(turret);
        }

        void PlaceTurrets(OrbitData orbit, LoadoutGenerator loadoutGenerator, int count)
        {
            for (int t = 0; t < count; t++)
            {
                var dist = t / 2;
                if (t % 2 == 0)
                {
                    dist = -dist;
                }
                PlaceTurret(orbit, loadoutGenerator, dist);
            }
        }

        for (var i = 0; i < storyStations.Length; i++)
        {
            var story         = storyStations[i];
            var orbit         = selectedStationOrbits[i];
            var lagrangeOrbit = CreateLagrangeOrbit(orbit);
            var station       = GetLoadoutGenerator(story.Faction).GenerateStationLoadout();
            station.Orbit          = lagrangeOrbit.ID;
            station.SecurityLevel  = story.Security;
            station.SecurityRadius = pack.Radius;
            station.Story          = i;
            pack.Entities.Add(station);

            PlaceTurrets(lagrangeOrbit, GetLoadoutGenerator(story.Faction), story.Turrets);
        }

        for (var i = storyStations.Length; i < selectedStationOrbits.Length; i++)
        {
            var orbit    = selectedStationOrbits[i];
            var security = (SecurityLevel)((int)((1f - pow(random.NextFloat(), factionPresence / 2f)) * 3f));

            var lagrangeOrbit = CreateLagrangeOrbit(orbit);
            var station       = GetLoadoutGenerator(nearestFaction).GenerateStationLoadout();
            station.Orbit          = lagrangeOrbit.ID;
            station.SecurityLevel  = security;
            station.SecurityRadius = pack.Radius;
            pack.Entities.Add(station);

            PlaceTurrets(lagrangeOrbit, GetLoadoutGenerator(nearestFaction), 2);
        }

        var enemyCount = (int)(random.NextFloat() * factionPresence * 2) + stationCount;

        for (int i = 0; i < enemyCount; i++)
        {
            pack.Entities.Add(GetLoadoutGenerator(nearestFaction).GenerateShipLoadout());
        }

        return(pack);
    }
Пример #7
0
 public HashSet <GalaxyZone> ConnectedRegion(
     GalaxyZone v,
     Predicate <(GalaxyZone source, GalaxyZone target)> linkFilter,
Пример #8
0
 public HashSet <GalaxyZone> ConnectedRegion(
     GalaxyZone v,
     int maxDistance = int.MaxValue)
 {
     return(ConnectedRegion(v, x => true, maxDistance));
 }
Пример #9
0
 public DistanceSelector(string[] args, IZoneResolver zoneResolver)
 {
     Target = zoneResolver.ResolveZone(args[0].Trim());
 }
Пример #10
0
 protected override bool TestZone(GalaxyZone zone)
 {
     return(_targetZone != null && _test(zone.Distance[_targetZone]));
 }
Пример #11
0
 protected override bool TestZone(GalaxyZone zone)
 {
     return(zone.Owner.ID == TargetFaction?.ID);
 }
Пример #12
0
 protected override bool TestZone(GalaxyZone zone)
 {
     return(zone.Factions.Any(f => f.ID == TargetFaction?.ID));
 }
Пример #13
0
 protected abstract bool TestZone(GalaxyZone zone);
Пример #14
0
 public bool Test(GalaxyZone zone)
 {
     return(Flip ^ TestZone(zone));
 }