Mini Galaxy Gen

Added flags to game manager and player settings to check tutorial status
Created alternate galaxy generation process for tutorial
This commit is contained in:
Reinier Vens 2021-04-22 02:53:06 +01:00
commit b1bd89a687
224 changed files with 423 additions and 208 deletions

View file

@ -1141,7 +1141,7 @@ public class EquippedItem
ThermalPerformance = Data.Performance(temp);
DurabilityPerformance = EquippableItem.Durability / Data.Durability;
var performanceThreshold = Entity.Settings.ShutdownPerformance;
Wear = (1 - pow(Data.Performance(temp),
Wear = (1 - pow(ThermalPerformance,
(1 - pow(EquippableItem.Quality, ItemManager.GameplaySettings.QualityWearExponent)) *
ItemManager.GameplaySettings.ThermalWearExponent)
) * Data.Durability / Data.ThermalResilience;

View file

@ -387,7 +387,7 @@ public abstract class EquippableItemData : CraftedItemData
public float Performance(float temperature)
{
return saturate(HeatPerformanceCurve.Evaluate(unlerp(MinimumTemperature, MaximumTemperature, temperature)));
return saturate(HeatPerformanceCurve?.Evaluate(unlerp(MinimumTemperature, MaximumTemperature, temperature))??1);
}
}

View file

@ -29,6 +29,18 @@ public class LoadoutGenerator
Faction = faction;
PriceExponent = priceExponent;
}
public LoadoutGenerator(
ref Random random,
ItemManager itemManager,
Faction faction,
float priceExponent)
{
Random = random;
ItemManager = itemManager;
Faction = faction;
PriceExponent = priceExponent;
}
public EntityPack GenerateShipLoadout(Predicate<HullData> hullFilter = null)
{
@ -89,12 +101,14 @@ public class LoadoutGenerator
.Where(item =>
item.Price > 0 &&
(hullFilter?.Invoke(item) ?? true) &&
item.HullType == type &&
item.HullType == type &&
item.Manufacturer != Guid.Empty &&
(Sector?.ContainsFaction(item.Manufacturer) ?? true) &&
(Faction == null || item.Manufacturer == Faction.ID || Faction.Allegiance.ContainsKey(item.Manufacturer)))
.WeightedRandomElements(ref Random,
item =>
(Faction == null || item.Manufacturer == Faction.ID ? 1 : Faction.Allegiance[item.Manufacturer]) / // Prioritize items from allied manufacturers
Zone.Distance[Sector.HomeZones[ItemManager.ItemData.Get<Faction>(item.Manufacturer)]] / // Penalize distance to manufacturer headquarters
(Zone?.Distance[Sector.HomeZones[ItemManager.ItemData.Get<Faction>(item.Manufacturer)]] ?? 1) / // Penalize distance to manufacturer headquarters
pow(item.Price, PriceExponent), // Penalize item price to a controllable degree
1
).FirstOrDefault();
@ -104,14 +118,15 @@ public class LoadoutGenerator
{
return ItemManager.ItemData.GetAll<T>()
.Where(item =>
item.Price > 0 &&
Sector.ContainsFaction(item.Manufacturer) &&
item.Price > 0 &&
item.Manufacturer != Guid.Empty &&
(Sector?.ContainsFaction(item.Manufacturer) ?? true) &&
(Faction == null || Faction.Allegiance.ContainsKey(item.Manufacturer)) &&
(filter?.Invoke(item) ?? true))
.WeightedRandomElements(ref Random, item =>
(Faction == null || item.Manufacturer == Faction.ID ? 1 : Faction.Allegiance[item.Manufacturer]) * // Prioritize items from allied manufacturers
pow(item.Shape.Coordinates.Length, sizeExponent) / // Prioritize larger items
Zone.Distance[Sector.HomeZones[ItemManager.ItemData.Get<Faction>(item.Manufacturer)]] / // Penalize distance to manufacturer headquarters
(Zone?.Distance[Sector.HomeZones[ItemManager.ItemData.Get<Faction>(item.Manufacturer)]] ?? 1) / // Penalize distance to manufacturer headquarters
pow(item.Price, PriceExponent), // Penalize item price to a controllable degree
count
);

View file

@ -20,7 +20,7 @@ public class MarkovNameGenerator
private int _maxLength;
private Random _random;
public MarkovNameGenerator(ref Random random, IEnumerable<string> sampleNames, SectorGenerationSettings settings)
public MarkovNameGenerator(ref Random random, IEnumerable<string> sampleNames, NameGeneratorSettings settings)
{
var names = new HashSet<string>();
foreach (var line in sampleNames)

View file

@ -9,6 +9,7 @@ public class PlayerSettings
[Key(1)] public SavedGame SavedRun;
[Key(2)] public TemperatureUnit TemperatureUnit = TemperatureUnit.Celsius;
[Key(3)] public int SignificantDigits = 3;
[Key(4)] public bool TutorialPassed;
public string FormatTemperature(float t)
{

View file

@ -87,11 +87,10 @@ public static class WeightedSampleElimination
}, densityFunc, d_max);
}
public static float2[] GeneratePoints(int count, Func<float2, float> density = null, Func<float2, float> envelope = null, Action<string> progressCallback = null, uint seed = 1337)
public static float2[] GeneratePoints(int count, ref Random random, Func<float2, float> density = null, Func<float2, float> envelope = null, Action<string> progressCallback = null)
{
if (density == null) density = v => .5f;
if (envelope == null) envelope = v => 1;
var random = new Random(seed);
var inputSamples = new float2[count * 8];
var sample = 0;
var accumulator = 0f;

View file

@ -33,20 +33,23 @@ public class SavedGame
public int CurrentZoneEntity;
[Key(8)]
public SectorGenerationSettings Settings;
public SectorBackgroundSettings Background;
[Key(9)]
public int[] DiscoveredZones;
[Key(10)]
public SavedActionBarBinding[] ActionBarBindings;
[Key(11)]
public bool IsTutorial;
public SavedGame() { }
public SavedGame(Sector sector, Zone currentZone, Entity currentEntity)
{
DiscoveredZones = sector.DiscoveredZones.Select(dz => Array.IndexOf(sector.Zones, dz)).ToArray();
Settings = sector.Settings;
Background = sector.Background;
Factions = sector.HomeZones.Keys.Select(f => f.ID).ToArray();
HomeZones = sector.HomeZones.ToDictionary(

View file

@ -17,7 +17,8 @@ public class Sector
public Dictionary<Faction, SectorZone> BossZones = new Dictionary<Faction, SectorZone>();
public HashSet<SectorZone> DiscoveredZones = new HashSet<SectorZone>();
public SectorGenerationSettings Settings { get; }
public SectorBackgroundSettings Background { get; }
public NameGeneratorSettings NameGeneratorSettings { get; }
public Faction[] Factions { get; }
public SectorZone[] Zones { get; }
public SectorZone Entrance { get; }
@ -31,13 +32,15 @@ public class Sector
{
get
{
return _exitPath ??= FindPath(Entrance, Exit);
if(Entrance!=null && Exit != null)
return _exitPath ??= FindPath(Entrance, Exit);
return null;
}
}
public Sector(CultCache cultCache, SavedGame savedGame)
{
Settings = savedGame.Settings;
Background = savedGame.Background;
Factions = savedGame.Factions.Select(cultCache.Get<Faction>).ToArray();
Zones = savedGame.Zones.Select(zone =>
{
@ -70,43 +73,265 @@ public class Sector
CalculateDistanceMatrix();
}
public Sector(SectorGenerationSettings settings, CultCache cultCache, uint seed = 0, Action<string> progressCallback = null, float minLineSeparation = .01f)
public Sector(
SectorGenerationSettings settings,
SectorBackgroundSettings background,
NameGeneratorSettings nameGeneratorSettings,
CultCache cache,
Action<string> progressCallback = null,
uint seed = 0)
{
Settings = settings;
var megas = cultCache.GetAll<Faction>();
Background = background;
var factions = cache.GetAll<Faction>();
var random = new Random(seed == 0 ? (uint) (DateTime.Now.Ticks % uint.MaxValue) : seed);
Factions = megas.OrderBy(x => random.NextFloat()).Take(settings.MegaCount).ToArray();
Factions = factions.OrderBy(x => random.NextFloat()).Take(settings.MegaCount).ToArray();
var outputSamples = WeightedSampleElimination.GeneratePoints(settings.ZoneCount,
settings.CloudDensity,
Zones = GenerateZones(settings.ZoneCount, ref random, progressCallback);
GenerateLinks(settings.LinkDensity, progressCallback);
CalculateDistanceMatrix(progressCallback);
// Exit is the most isolated zone (highest total distance to all other zones)
Exit = Zones.MaxBy(z => z.Isolation);
// Entrance is the zone furthest from the exit
Entrance = Zones.MaxBy(z => Exit.Distance[z]);
DiscoveredZones.Add(Entrance);
foreach(var z in Entrance.AdjacentZones) DiscoveredZones.Add(z);
PlaceFactionsMain(settings.BossCount, progressCallback);
CalculateFactionInfluence(progressCallback);
GenerateNames(cache, nameGeneratorSettings, ref random, progressCallback);
progressCallback?.Invoke("Done!");
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
}
public Sector(
TutorialGenerationSettings settings,
SectorBackgroundSettings background,
NameGeneratorSettings nameGeneratorSettings,
CultCache cache,
Action<string> progressCallback = null,
uint seed = 0)
{
Background = background;
var allFactions = cache.GetAll<Faction>();
var random = new Random(seed == 0 ? (uint) (DateTime.Now.Ticks % uint.MaxValue) : seed);
var factions = new List<Faction>();
var protagonistFaction = allFactions.First(f => f.Name.StartsWith(settings.ProtagonistFaction, StringComparison.InvariantCultureIgnoreCase));
factions.Add(protagonistFaction);
var antagonistFaction = allFactions.First(f => f.Name.StartsWith(settings.AntagonistFaction, StringComparison.InvariantCultureIgnoreCase));
factions.Add(antagonistFaction);
var bufferFaction = allFactions.First(f => f.Name.StartsWith(settings.BufferFaction, StringComparison.InvariantCultureIgnoreCase));
factions.Add(bufferFaction);
var questFaction = allFactions.First(f => f.Name.StartsWith(settings.QuestFaction, StringComparison.InvariantCultureIgnoreCase));
factions.Add(questFaction);
var neutralFactions = settings.NeutralFactions
.Select(s => allFactions.First(f => f.Name.StartsWith(s, StringComparison.InvariantCultureIgnoreCase)))
.ToArray();
factions.AddRange(neutralFactions);
Factions = factions.ToArray();
foreach (var faction in Factions) faction.InfluenceDistance = (faction.InfluenceDistance + 1) / 2;
Zones = GenerateZones(settings.ZoneCount, ref random, progressCallback);
GenerateLinks(settings.LinkDensity, progressCallback);
CalculateDistanceMatrix(progressCallback);
HomeZones[protagonistFaction] = Zones
.MaxBy(z => ConnectedRegion(z, protagonistFaction.InfluenceDistance).Count);
HomeZones[antagonistFaction] = Zones
.MaxBy(z => ConnectedRegion(z, antagonistFaction.InfluenceDistance).Count * z.Distance[HomeZones[protagonistFaction]]);
HomeZones[protagonistFaction] = Zones
.MaxBy(z => ConnectedRegion(z, protagonistFaction.InfluenceDistance).Count * sqrt(z.Distance[HomeZones[antagonistFaction]]));
// var antagonistRegion = ConnectedRegion(HomeZones[antagonistFaction], antagonistFaction.InfluenceDistance);
// var protagonistRegion = ConnectedRegion(HomeZones[protagonistFaction], protagonistFaction.InfluenceDistance);
// Place the buffer faction in a zone where it has equal distance to the pro/antagonist HQs and where it can control the most territory
var bufferDistance = Zones.Min(z => abs(z.Distance[HomeZones[antagonistFaction]] - z.Distance[HomeZones[protagonistFaction]]));
var potentialBufferZones = Zones
.Where(z => abs(z.Distance[HomeZones[antagonistFaction]] - z.Distance[HomeZones[protagonistFaction]]) == bufferDistance);
HomeZones[bufferFaction] = potentialBufferZones.MaxBy(z => ConnectedRegion(z, bufferFaction.InfluenceDistance).Count);
// Place neutral headquarters away from existing factions while also maximizing territory
foreach (var faction in neutralFactions)
{
HomeZones[faction] = Zones.MaxBy(z =>
ConnectedRegion(z, faction.InfluenceDistance).Count *
HomeZones.Values.Aggregate(1f, (i, os) => i * sqrt(os.Distance[z])));
}
CalculateFactionInfluence(progressCallback);
var potentialQuestZones = Zones
.Where(z => z.Factions.Contains(antagonistFaction) && z.Factions.Contains(bufferFaction));
HomeZones[questFaction] = potentialQuestZones
.MaxBy(z=>z.Distance[HomeZones[antagonistFaction]] * ConnectedRegion(z, questFaction.InfluenceDistance).Count);
CalculateFactionInfluence(progressCallback);
Entrance = ConnectedRegion(HomeZones[protagonistFaction], 2)
.MaxBy(z => z.Distance[HomeZones[antagonistFaction]]);
DiscoveredZones.Add(Entrance);
foreach(var z in Entrance.AdjacentZones) DiscoveredZones.Add(z);
CalculateFactionInfluence(progressCallback);
GenerateNames(cache, nameGeneratorSettings, ref random, progressCallback);
progressCallback?.Invoke("Done!");
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
}
private SectorZone[] GenerateZones(int zoneCount, ref Random random, Action<string> progressCallback = null)
{
var outputSamples = WeightedSampleElimination.GeneratePoints(zoneCount,
ref random,
Background.CloudDensity,
v => (.2f - lengthsq(v - float2(.5f))) * 4,
progressCallback);
Zones = outputSamples.Select(v => new SectorZone {Position = v}).ToArray();
return outputSamples.Select(v => new SectorZone {Position = v}).ToArray();
}
#region Link Placement
progressCallback?.Invoke("Triangulating Zone Positions");
private void PlaceFactionsMain(int bossCount, Action<string> progressCallback = null)
{
progressCallback?.Invoke("Finding Chokepoints");
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
// Find all zones on the exit path where removing that zone would disconnect the entrance from the exit
// Disregard "corridor" zones with only two adjacent zones
var chokePoints = ExitPath
.Where(z => z.AdjacentZones.Count > 2 && !ConnectedRegion(Entrance, z).Contains(Exit));
progressCallback?.Invoke("Placing Factions");
if (progressCallback != null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
// Choose some megas to have bosses placed based on whether a boss hull is assigned
var bossMegas = Factions
.Where(m => m.BossHull != Guid.Empty)
.Take(bossCount)
.ToArray();
// Place boss zones along the critical path as far apart from each other as possible
foreach (var mega in bossMegas)
{
BossZones[mega] = chokePoints.MaxBy(z =>
Exit.Distance[z] * Entrance.Distance[z] *
BossZones.Values.Aggregate(1, (i, os) => i * os.Distance[z]));
}
// Place boss mega headquarters such that their sphere of influence encompasses their boss zone
// While occupying as much territory as possible
foreach (var mega in bossMegas)
{
HomeZones[mega] = ConnectedRegion(BossZones[mega], mega.InfluenceDistance)
.MaxBy(z =>
ConnectedRegion(z, mega.InfluenceDistance).Count *
HomeZones.Values.Aggregate(1f, (i, os) => i * sqrt(os.Distance[z])));
}
// Place remaining headquarters away from existing megas while also maximizing territory
foreach (var mega in Factions.Where(m => !bossMegas.Contains(m)))
{
HomeZones[mega] = Zones.MaxBy(z =>
pow(ConnectedRegion(z, mega.InfluenceDistance).Count, HomeZones.Count) *
Exit.Distance[z] * Entrance.Distance[z] *
HomeZones.Values.Aggregate(1f, (i, os) => i * sqrt(os.Distance[z])) *
BossZones.Values.Aggregate(1f, (i, os) => i * sqrt(os.Distance[z])));
}
}
private void CalculateFactionInfluence(Action<string> progressCallback = null)
{
progressCallback?.Invoke("Calculating Faction Influence");
if (progressCallback != null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
// Assign faction presence
foreach (var zone in Zones)
{
// Factions are present in all zones within their sphere of influence
zone.Factions = Factions
.Where(f => HomeZones.ContainsKey(f))
.Where(f => zone.Distance[HomeZones[f]] <= f.InfluenceDistance)
.ToArray();
// Owner of a zone is the faction with the nearest headquarters
var nearestFaction = Factions
.Where(f => HomeZones.ContainsKey(f))
.MinBy(f => (float)zone.Distance[HomeZones[f]]);
if (zone.Distance[HomeZones[nearestFaction]] <= nearestFaction.InfluenceDistance)
zone.Owner = nearestFaction;
}
}
private void GenerateNames(CultCache cache,
NameGeneratorSettings nameGeneratorSettings,
ref Random random,
Action<string> progressCallback = null)
{
for (var i = 0; i < Factions.Length; i++)
{
progressCallback?.Invoke($"Feeding Markov Chains: {i + 1} / {Factions.Length}");
//if(progressCallback!=null) Thread.Sleep(250); // Inserting Delay to make it seem like it's doing more work lmao
var faction = Factions[i];
_nameGenerators[faction] = new MarkovNameGenerator(ref random, cache.Get<NameFile>(faction.GeonameFile).Names, nameGeneratorSettings);
}
// Generate zone name using the owner's name generator, otherwise assign catalogue ID
foreach (var zone in Zones)
{
if (zone.Owner != null)
{
zone.Name = _nameGenerators[zone.Owner].NextName.Trim();
}
else
{
zone.Name = $"EAC-{random.NextInt(9999).ToString()}";
}
}
}
private void GenerateLinks(float linkDensity, Action<string> progressCallback = null)
{
progressCallback?.Invoke("Triangulating Zone Positions");
if (progressCallback != null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
// Create a delaunay triangulation to connect adjacent sectors
var triangulation = DelaunayTriangulation<Vertex2<SectorZone>, Cell2<SectorZone>>
.Create(Zones.Select(z => new Vertex2<SectorZone>(z.Position, z)).ToList(), 1e-7f);
var links = new HashSet<(SectorZone, SectorZone)>();
foreach(var cell in triangulation.Cells)
foreach (var cell in triangulation.Cells)
{
if(!links.Contains((cell.Vertices[0].StoredObject, cell.Vertices[1].StoredObject)) &&
!links.Contains((cell.Vertices[1].StoredObject, cell.Vertices[0].StoredObject)))
if (!links.Contains((cell.Vertices[0].StoredObject, cell.Vertices[1].StoredObject)) &&
!links.Contains((cell.Vertices[1].StoredObject, cell.Vertices[0].StoredObject)))
links.Add((cell.Vertices[0].StoredObject, cell.Vertices[1].StoredObject));
if(!links.Contains((cell.Vertices[1].StoredObject, cell.Vertices[2].StoredObject)) &&
!links.Contains((cell.Vertices[2].StoredObject, cell.Vertices[1].StoredObject)))
if (!links.Contains((cell.Vertices[1].StoredObject, cell.Vertices[2].StoredObject)) &&
!links.Contains((cell.Vertices[2].StoredObject, cell.Vertices[1].StoredObject)))
links.Add((cell.Vertices[1].StoredObject, cell.Vertices[2].StoredObject));
if(!links.Contains((cell.Vertices[0].StoredObject, cell.Vertices[2].StoredObject)) &&
!links.Contains((cell.Vertices[2].StoredObject, cell.Vertices[0].StoredObject)))
if (!links.Contains((cell.Vertices[0].StoredObject, cell.Vertices[2].StoredObject)) &&
!links.Contains((cell.Vertices[2].StoredObject, cell.Vertices[0].StoredObject)))
links.Add((cell.Vertices[0].StoredObject, cell.Vertices[2].StoredObject));
}
progressCallback?.Invoke("Eliminating Zone Links");
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
if (progressCallback != null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
// foreach (var link in links.ToArray())
// {
// foreach (var zone in Zones)
@ -125,17 +350,17 @@ public class Sector
float LinkWeight((SectorZone, SectorZone) link)
{
return 1 / saturate(settings.CloudDensity((link.Item1.Position + link.Item2.Position) / 2)) *
return 1 / saturate(Background.CloudDensity((link.Item1.Position + link.Item2.Position) / 2)) *
lengthsq(link.Item1.Position - link.Item2.Position) *
(link.Item1.AdjacentZones.Count - 1) * (link.Item2.AdjacentZones.Count - 1);
}
var heap = new MaxHeap<(SectorZone, SectorZone)>(links.Count);
foreach(var link in links) heap.PushObj(link, LinkWeight(link));
while (heap.Count > settings.LinkDensity * links.Count)
foreach (var link in links) heap.PushObj(link, LinkWeight(link));
while (heap.Count > linkDensity * links.Count)
{
var link = heap.PopObj();
if(ConnectedRegion(link.Item1, link.Item1, link.Item2).Contains(link.Item2))
if (ConnectedRegion(link.Item1, link.Item1, link.Item2).Contains(link.Item2))
{
link.Item1.AdjacentZones.Remove(link.Item2);
link.Item2.AdjacentZones.Remove(link.Item1);
@ -152,108 +377,18 @@ public class Sector
}
}
}
}
#endregion
// Cache distance matrix and calculate isolation for every zone (used extensively for placing stuff)
private void CalculateDistanceMatrix(Action<string> progressCallback = null)
{
progressCallback?.Invoke("Calculating Distance Matrix");
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
CalculateDistanceMatrix();
progressCallback?.Invoke("Finding Chokepoints");
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
// Exit is the most isolated zone (highest total distance to all other zones)
Exit = Zones.MaxBy(z => z.Isolation);
// Entrance is the zone furthest from the exit
Entrance = Zones.MaxBy(z => Exit.Distance[z]);
DiscoveredZones.Add(Entrance);
foreach(var z in Entrance.AdjacentZones) DiscoveredZones.Add(z);
// Find all zones on the exit path where removing that zone would disconnect the entrance from the exit
// Disregard "corridor" zones with only two adjacent zones
var chokePoints = ExitPath
.Where(z => z.AdjacentZones.Count > 2 && !ConnectedRegion(Entrance, z).Contains(Exit));
progressCallback?.Invoke("Placing Factions");
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
// Choose some megas to have bosses placed based on whether a boss hull is assigned
var bossMegas = Factions
.Where(m => m.BossHull != Guid.Empty)
.Take(settings.BossCount)
.ToArray();
// Place boss zones along the critical path as far apart from each other as possible
foreach (var mega in bossMegas)
{
BossZones[mega] = chokePoints.MaxBy(z =>
Exit.Distance[z] * Entrance.Distance[z] *
BossZones.Values.Aggregate(1, (i, os) => i * os.Distance[z]));
}
// Place boss mega headquarters such that their sphere of influence encompasses their boss zone
// While occupying as much territory as possible
foreach (var mega in bossMegas)
{
HomeZones[mega] = ConnectedRegion(BossZones[mega], mega.InfluenceDistance)
.MaxBy(z =>
ConnectedRegion(z, mega.InfluenceDistance).Count *
HomeZones.Values.Aggregate(1f, (i, os) => i * sqrt(os.Distance[z])));
}
// Place remaining headquarters away from existing megas while also maximizing territory
foreach (var mega in Factions.Where(m=>!bossMegas.Contains(m)))
{
HomeZones[mega] = Zones.MaxBy(z =>
pow(ConnectedRegion(z, mega.InfluenceDistance).Count, HomeZones.Count) *
Exit.Distance[z] * Entrance.Distance[z] *
HomeZones.Values.Aggregate(1f, (i, os) => i * sqrt(os.Distance[z])) *
BossZones.Values.Aggregate(1f, (i, os) => i * sqrt(os.Distance[z])));
}
progressCallback?.Invoke("Calculating Faction Influence");
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
// Assign faction presence
foreach (var zone in Zones)
{
// Factions are present in all zones within their sphere of influence
zone.Factions = Factions
.Where(m => zone.Distance[HomeZones[m]] <= m.InfluenceDistance)
.ToArray();
// Owner of a zone is the faction with the nearest headquarters
var nearestFaction = Factions.MinBy(m => zone.Distance[HomeZones[m]]);
if (zone.Distance[HomeZones[nearestFaction]] <= nearestFaction.InfluenceDistance)
zone.Owner = nearestFaction;
zone.Distance = ConnectedRegionDistance(zone);
zone.Isolation = zone.Distance.Sum(x => x.Value);
}
for (var i = 0; i < Factions.Length; i++)
{
progressCallback?.Invoke($"Feeding Markov Chains: {i+1} / {Factions.Length}");
//if(progressCallback!=null) Thread.Sleep(250); // Inserting Delay to make it seem like it's doing more work lmao
var faction = Factions[i];
_nameGenerators[faction] = new MarkovNameGenerator(ref random, cultCache.Get<NameFile>(faction.GeonameFile).Names, settings);
}
// Generate zone name using the owner's name generator, otherwise assign catalogue ID
foreach (var zone in Zones)
{
if (zone.Owner != null)
{
zone.Name = _nameGenerators[zone.Owner].NextName.Trim();
}
else
{
zone.Name = $"EAC-{random.NextInt(9999).ToString()}";
}
}
progressCallback?.Invoke("Done!");
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
}
public bool ContainsFaction(Guid factionID)
@ -262,16 +397,6 @@ public class Sector
return _containedFactions.Contains(factionID);
}
// Cache distance matrix and calculate isolation for every zone (used extensively for placing stuff)
private void CalculateDistanceMatrix()
{
foreach (var zone in Zones)
{
zone.Distance = ConnectedRegionDistance(zone);
zone.Isolation = zone.Distance.Sum(x => x.Value);
}
}
class DijkstraVertex
{
public float Cost;

View file

@ -44,23 +44,24 @@ public class GalaxyShapeSettings
}
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
public class SectorGenerationSettings
public class NameGeneratorSettings
{
public float LinkDensity = .5f;
public int ZoneCount = 128;
public int NameGeneratorMinLength = 5;
public int NameGeneratorMaxLength = 10;
public int NameGeneratorOrder = 4;
public int MegaCount;
public int BossCount;
public float NoisePosition;
public float CloudExponent;
public float CloudAmplitude;
}
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
public class SectorBackgroundSettings
{
public float NoiseAmplitude;
public float NoiseOffset;
public float NoiseGain;
public float NoiseLacunarity;
public float NoiseFrequency;
public float NoisePosition;
public float CloudExponent;
public float CloudAmplitude;
public float fBm(float2 p, int octaves)
{
@ -84,6 +85,27 @@ public class SectorGenerationSettings
}
}
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
public class SectorGenerationSettings
{
public float LinkDensity = .5f;
public int ZoneCount = 128;
public int MegaCount;
public int BossCount;
}
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
public class TutorialGenerationSettings
{
public string ProtagonistFaction;
public string AntagonistFaction;
public string BufferFaction;
public string[] NeutralFactions;
public string QuestFaction;
public float LinkDensity = .5f;
public int ZoneCount = 32;
}
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
public class ZoneGenerationSettings
{

View file

@ -39,13 +39,14 @@ public static class ZoneGenerator
ItemManager itemManager,
ZoneGenerationSettings zoneSettings,
Sector sector,
SectorZone sectorZone)
SectorZone sectorZone,
bool isTutorial = false)
{
var pack = new ZonePack();
var random = new Random(unchecked((uint) sectorZone.Name.GetHashCode()) ^ hash(sectorZone.Position));
var density = saturate(sector.Settings.CloudDensity(sectorZone.Position));
var density = saturate(sector.Background.CloudDensity(sectorZone.Position));
pack.Radius = zoneSettings.ZoneRadius.Evaluate(density);
pack.Mass = zoneSettings.ZoneMass.Evaluate(density);
var targetSubzoneCount = zoneSettings.SubZoneCount.Evaluate(density);
@ -225,7 +226,8 @@ public static class ZoneGenerator
var nearestFactionHomeZone = sector.HomeZones[nearestFaction];
var factionPresence = nearestFaction.InfluenceDistance - nearestFactionHomeZone.Distance[sectorZone] + 1;
var loadoutGenerator = new LoadoutGenerator(ref random, itemManager, sector, sectorZone, nearestFaction, .5f);
var loadoutGenerator = isTutorial ? new LoadoutGenerator(ref random, itemManager, nearestFaction, .5f) :
new LoadoutGenerator(ref random, itemManager, sector, sectorZone, nearestFaction, .5f);
for (int i = 0; i < factionPresence; i++)
{
pack.Entities.Add(loadoutGenerator.GenerateShipLoadout());