Hostility Fix + Story Work

Fixed various bugs caused by triggering wormhole animation multiple times
Sector -> Galaxy
Fixed bug in hostility system; deserialized entities' PresencePermitted was silently throwing an exception (due to Faction being null during initialization) and thus never updating in response to security level changes
Worked a bit on story processing
This commit is contained in:
Reinier Vens 2021-05-14 03:03:28 +01:00
commit 2f98904614
26 changed files with 301 additions and 255 deletions

View file

@ -146,6 +146,15 @@ public abstract class Entity
//ItemManager.Log($"Entity {Name} is activating!");
_active = true;
Heatstroke = 0;
// The entity's presence is permitted when its faction owns the zone, or the current security level at its location is low enough
PresencePermitted = new ReadOnlyReactiveProperty<bool>(CurrentSecurityLevel.Select(security =>
{
var factionRelationship = GetFactionRelationship(Zone.GalaxyZone.Owner);
var presencePermitted = IsPresencePermitted(factionRelationship, security);
return presencePermitted;
}), initialValue: true);
foreach (var item in Equipment)
foreach (var behavior in item.Behaviors)
{
@ -269,9 +278,7 @@ public abstract class Entity
.Merge(HypothermiaDeath.Select(_ => CauseOfDeath.Hypothermia))
.Merge(ItemDestroyed.Where(i=>i.GetBehavior<Cockpit>()!=null).Select(_ => CauseOfDeath.CockpitDestroyed));
// The entity's presence is permitted when its faction owns the zone, or the current security level at its location is low enough
PresencePermitted = new ReadOnlyReactiveProperty<bool>(CurrentSecurityLevel.Select(security =>
IsPresencePermitted(GetFactionRelationship(Zone.SectorZone.Owner), security)), true);
//CurrentSecurityLevel.Value = SecurityLevel.Open;
}
public bool IsHostileTo(Entity other, bool recursive = false)
@ -281,8 +288,8 @@ public abstract class Entity
// TODO: Inter-faction hostility
// When the entity faction owns the zone, they are hostile to trespassers or those hostile to them
if (Faction.ID == Zone.SectorZone.Owner.ID)
return recursive ? !other.PresencePermitted.Value : !other.PresencePermitted.Value || other.IsHostileTo(this, true);
if (Faction.ID == Zone.GalaxyZone.Owner.ID)
return recursive ? !(other.PresencePermitted?.Value ?? true) : !(other.PresencePermitted?.Value ?? true)|| other.IsHostileTo(this, true);
return !recursive && other.IsHostileTo(this, true);
}
@ -293,7 +300,7 @@ public abstract class Entity
if (faction == null)
return FactionRelationship.Neutral;
if (this is Ship {IsPlayerShip: true})
return Zone.Sector.FactionRelationships[faction];
return Zone.Galaxy.FactionRelationships[faction];
return faction.ID == Faction.ID ? FactionRelationship.Beloved : FactionRelationship.Neutral;
}

View file

@ -165,6 +165,12 @@ public enum CompoundCommodityCategory
Assemblies = 5
}
public enum LocationType
{
Station,
Planet
}
public enum FactionRelationship
{
Hated = 0, // Kill on sight

View file

@ -5,6 +5,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DataStructures.ViliWonka.Heap;
using Ink.Runtime;
using MIConvexHull;
using JM.LinqFaster;
using UniRx;
@ -12,25 +13,25 @@ using Unity.Mathematics;
using static Unity.Mathematics.math;
using Random = Unity.Mathematics.Random;
public class Sector
public class Galaxy
{
public Dictionary<Faction, SectorZone> HomeZones = new Dictionary<Faction, SectorZone>();
public Dictionary<Faction, SectorZone> BossZones = new Dictionary<Faction, SectorZone>();
public HashSet<SectorZone> DiscoveredZones = new HashSet<SectorZone>();
public Dictionary<Faction, GalaxyZone> HomeZones = new Dictionary<Faction, GalaxyZone>();
public Dictionary<Faction, GalaxyZone> BossZones = new Dictionary<Faction, GalaxyZone>();
public HashSet<GalaxyZone> DiscoveredZones = new HashSet<GalaxyZone>();
public SectorBackgroundSettings Background { get; }
public NameGeneratorSettings NameGeneratorSettings { get; }
public Faction[] Factions { get; }
public SectorZone[] Zones { get; }
public SectorZone Entrance { get; }
public SectorZone Exit { get; }
public GalaxyZone[] Zones { get; }
public GalaxyZone Entrance { get; }
public GalaxyZone Exit { get; }
public Dictionary<Faction, FactionRelationship> FactionRelationships { get; } = new Dictionary<Faction, FactionRelationship>();
private HashSet<Guid> _containedFactions;
private SectorZone[] _exitPath;
private GalaxyZone[] _exitPath;
private Dictionary<Faction, MarkovNameGenerator> _nameGenerators = new Dictionary<Faction, MarkovNameGenerator>();
public SectorZone[] ExitPath
public GalaxyZone[] ExitPath
{
get
{
@ -40,7 +41,7 @@ public class Sector
}
}
public Sector(CultCache cultCache, SavedGame savedGame)
public Galaxy(CultCache cultCache, SavedGame savedGame)
{
Background = savedGame.Background;
@ -52,7 +53,7 @@ public class Sector
Zones = savedGame.Zones.Select(zone =>
{
return new SectorZone
return new GalaxyZone
{
Name = zone.Name,
Position = zone.Position,
@ -82,7 +83,7 @@ public class Sector
CalculateDistanceMatrix();
}
public Sector(
public Galaxy(
SectorGenerationSettings settings,
SectorBackgroundSettings background,
NameGeneratorSettings nameGeneratorSettings,
@ -121,7 +122,7 @@ public class Sector
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
}
public Sector(
public Galaxy(
TutorialGenerationSettings settings,
SectorBackgroundSettings background,
NameGeneratorSettings nameGeneratorSettings,
@ -229,14 +230,14 @@ public class Sector
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)
private GalaxyZone[] 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);
return outputSamples.Select(v => new SectorZone {Position = v}).ToArray();
return outputSamples.Select(v => new GalaxyZone {Position = v}).ToArray();
}
private void PlaceFactionsMain(int bossCount, Action<string> progressCallback = null)
@ -343,9 +344,9 @@ public class Sector
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)>();
var triangulation = DelaunayTriangulation<Vertex2<GalaxyZone>, Cell2<GalaxyZone>>
.Create(Zones.Select(z => new Vertex2<GalaxyZone>(z.Position, z)).ToList(), 1e-7f);
var links = new HashSet<(GalaxyZone, GalaxyZone)>();
foreach (var cell in triangulation.Cells)
{
if (!links.Contains((cell.Vertices[0].StoredObject, cell.Vertices[1].StoredObject)) &&
@ -377,14 +378,14 @@ public class Sector
link.Item2.AdjacentZones.Add(link.Item1);
}
float LinkWeight((SectorZone, SectorZone) link)
float LinkWeight((GalaxyZone, GalaxyZone) link)
{
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);
var heap = new MaxHeap<(GalaxyZone, GalaxyZone)>(links.Count);
foreach (var link in links) heap.PushObj(link, LinkWeight(link));
while (heap.Count > linkDensity * links.Count)
{
@ -430,12 +431,12 @@ public class Sector
{
public float Cost;
public DijkstraVertex Parent;
public SectorZone Zone;
public GalaxyZone Zone;
}
public Dictionary<SectorZone, int> ConnectedRegionDistance(SectorZone v)
public Dictionary<GalaxyZone, int> ConnectedRegionDistance(GalaxyZone v)
{
var members = new Dictionary<SectorZone, int> {{v, 0}};
var members = new Dictionary<GalaxyZone, int> {{v, 0}};
int cost = 1;
while (true)
{
@ -455,36 +456,36 @@ public class Sector
}
}
public HashSet<SectorZone> ConnectedRegion(
SectorZone v,
SectorZone ignoreLinkSource,
SectorZone ignoreLinkTarget,
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);
}
public HashSet<SectorZone> ConnectedRegion(
SectorZone v,
SectorZone ignoreZone,
public HashSet<GalaxyZone> ConnectedRegion(
GalaxyZone v,
GalaxyZone ignoreZone,
int maxDistance = int.MaxValue)
{
return ConnectedRegion(v, x => x.Item2 != ignoreZone, maxDistance);
}
public HashSet<SectorZone> ConnectedRegion(
SectorZone v,
public HashSet<GalaxyZone> ConnectedRegion(
GalaxyZone v,
int maxDistance = int.MaxValue)
{
return ConnectedRegion(v, x => true, maxDistance);
}
public HashSet<SectorZone> ConnectedRegion(
SectorZone v,
Predicate<(SectorZone source, SectorZone target)> linkFilter,
public HashSet<GalaxyZone> ConnectedRegion(
GalaxyZone v,
Predicate<(GalaxyZone source, GalaxyZone target)> linkFilter,
int maxDistance = int.MaxValue)
{
var visited = new HashSet<SectorZone> {v};
var visited = new HashSet<GalaxyZone> {v};
int cost = 1;
while (true)
{
@ -504,12 +505,12 @@ public class Sector
}
}
public SectorZone[] FindPath(SectorZone source, SectorZone target, bool bestFirst = false)
public GalaxyZone[] FindPath(GalaxyZone source, GalaxyZone target, bool bestFirst = false)
{
MinHeap<DijkstraVertex> unsearchedNodes = new MinHeap<DijkstraVertex>();
unsearchedNodes.PushObj(new DijkstraVertex{Zone = source}, 0);
//SortedList<float,DijkstraVertex> members = new SortedList<float,DijkstraVertex>{{0, new DijkstraVertex{Zone = source}}};
var searched = new HashSet<SectorZone>();
var searched = new HashSet<GalaxyZone>();
while (true)
{
if(unsearchedNodes.Count == 0) return null; // No nodes left unsearched
@ -523,7 +524,7 @@ public class Sector
return path.Select(dv => dv.Zone).ToArray();
}
// For each adjacent star (filter already visited stars unless heuristic is in use)
IEnumerable<SectorZone> zonesToSearch = s.Zone.AdjacentZones;
IEnumerable<GalaxyZone> zonesToSearch = s.Zone.AdjacentZones;
if (!bestFirst) zonesToSearch = zonesToSearch.Where(z => !searched.Contains(z));
foreach (var dijkstraStar in zonesToSearch
// Cost is parent cost plus distance squared
@ -535,15 +536,33 @@ public class Sector
}
}
public class SectorZone
public class GalaxyZone
{
public string Name;
public float2 Position;
public List<SectorZone> AdjacentZones = new List<SectorZone>();
public List<GalaxyZone> AdjacentZones = new List<GalaxyZone>();
public int Isolation;
public Dictionary<SectorZone, int> Distance;
public Dictionary<GalaxyZone, int> Distance;
public Faction[] Factions;
public Faction Owner;
public Zone Contents;
public ZonePack PackedContents;
public bool NamedZone;
public List<LocationStory> Locations = new List<LocationStory>();
}
public class GalaxyQuest
{
public Story Story;
public Dictionary<string, LocationStory> Locations = new Dictionary<string, LocationStory>();
}
public class LocationStory
{
public string FileName;
public string Name;
public Story Story;
public Faction Faction;
public SecurityLevel Security;
public LocationType Type;
}

View file

@ -10,22 +10,22 @@ public class LoadoutGenerator
{
public Random Random;
public ItemManager ItemManager { get; }
public Sector Sector { get; }
public SectorZone Zone { get; }
public Galaxy Galaxy { get; }
public GalaxyZone Zone { get; }
public Faction Faction { get; }
public float PriceExponent { get; }
public LoadoutGenerator(
ref Random random,
ItemManager itemManager,
Sector sector,
SectorZone zone,
Galaxy galaxy,
GalaxyZone zone,
Faction faction,
float priceExponent)
{
Random = random;
ItemManager = itemManager;
Sector = sector;
Galaxy = galaxy;
Zone = zone;
Faction = faction;
PriceExponent = priceExponent;
@ -107,12 +107,12 @@ public class LoadoutGenerator
(hullFilter?.Invoke(item) ?? true) &&
item.HullType == type &&
item.Manufacturer != Guid.Empty &&
(Sector?.ContainsFaction(item.Manufacturer) ?? true) &&
(Galaxy?.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)]] ?? 1) / // Penalize distance to manufacturer headquarters
(Zone?.Distance[Galaxy.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();
@ -124,13 +124,13 @@ public class LoadoutGenerator
.Where(item =>
item.Price > 0 &&
item.Manufacturer != Guid.Empty &&
(Sector?.ContainsFaction(item.Manufacturer) ?? true) &&
(Galaxy?.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)]] ?? 1) / // Penalize distance to manufacturer headquarters
(Zone?.Distance[Galaxy.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

@ -4,10 +4,11 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Ink;
using Ink.Runtime;
using Ink.Parsed;
using MessagePack;
using Path = System.IO.Path;
using Random = Unity.Mathematics.Random;
using Story = Ink.Runtime.Story;
public class StoryProcessor : IZoneResolver, IFactionResolver
{
@ -24,62 +25,67 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
public string LoadInkFileContents (string fullFilename) => File.ReadAllText (fullFilename);
}
private Dictionary<Story, SectorZone> _placedStories = new Dictionary<Story, SectorZone>();
private Dictionary<Story, string[]> _storyKnotPaths = new Dictionary<Story, string[]>();
private Dictionary<Story, GalaxyZone> _storyLocations = new Dictionary<Story, GalaxyZone>();
private Dictionary<string, Story> _processedStories = new Dictionary<string, Story>();
private DirectoryInfo _locationsPath;
private DirectoryInfo _questsPath;
private IFileHandler _inkFileHandler;
public DirectoryInfo NarrativeDirectory { get; }
private Random _random;
public Sector Sector { get; }
public Galaxy Galaxy { get; }
public PlayerSettings Settings { get; }
public StoryProcessor(PlayerSettings settings, DirectoryInfo narrativeDirectory, Sector sector, ref Random random)
public StoryProcessor(PlayerSettings settings, DirectoryInfo narrativeDirectory, Galaxy galaxy, ref Random random)
{
NarrativeDirectory = narrativeDirectory;
Sector = sector;
Galaxy = galaxy;
_random = random;
Settings = settings;
_inkFileHandler = new AetheriaInkFileHandler(narrativeDirectory);
_locationsPath = narrativeDirectory.CreateSubdirectory("Locations");
_questsPath = narrativeDirectory.CreateSubdirectory("Quests");
}
public Dictionary<Story, SectorZone> PlaceStories()
public void ProcessStories()
{
var locationFiles = _locationsPath.EnumerateFiles("*.ink");
foreach(var inkFile in locationFiles) PlaceStory(GetStory(inkFile));
return _placedStories;
foreach(var inkFile in locationFiles) ProcessLocation(GetStory(inkFile), inkFile);
var questFiles = _questsPath.EnumerateFiles("*ink");
foreach(var inkFile in questFiles) ProcessQuest(GetStory(inkFile));
}
public SectorZone ResolveZone(string path)
public GalaxyZone ResolveZone(string path)
{
// Handle special cases: "start" and "end"
if (path.Equals("start", StringComparison.InvariantCultureIgnoreCase))
return Sector.Entrance;
return Galaxy.Entrance;
if (path.Equals("end", StringComparison.InvariantCultureIgnoreCase))
return Sector.Exit;
return Galaxy.Exit;
// Handle faction home reference: format = "home.<faction>"
if(path.StartsWith("home"))
{
var factionString = path.Substring(5);
var faction = ResolveFaction(factionString);
return !Sector.HomeZones.ContainsKey(faction) ? null : Sector.HomeZones[faction];
return !Galaxy.HomeZones.ContainsKey(faction) ? null : Galaxy.HomeZones[faction];
}
var locationInkFile = new FileInfo(Path.Combine(_locationsPath.FullName, $"{path}.ink"));
if (!locationInkFile.Exists) return null;
var story = GetStory(locationInkFile);
PlaceStory(story);
return _placedStories.ContainsKey(story) ? _placedStories[story] : null;
ProcessLocation(story, locationInkFile);
return _storyLocations.ContainsKey(story) ? _storyLocations[story] : null;
}
public Faction ResolveFaction(string name)
{
return Sector.Factions.FirstOrDefault(f => f.Name.StartsWith(name, StringComparison.InvariantCultureIgnoreCase));
return Galaxy.Factions.FirstOrDefault(f => f.Name.StartsWith(name, StringComparison.InvariantCultureIgnoreCase));
}
Story GetStory(FileInfo inkFile)
@ -109,16 +115,30 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
fileHandler = _inkFileHandler
});
var story = compiler.Compile();
var knots = compiler.parsedStory.FindAll<Knot>().Select(k=>k.runtimePath.ToString()).ToArray();
_storyKnotPaths[story] = knots;
File.WriteAllText(compiledFileName, story.ToJson());
return story;
}
public void PlaceStory(Story story)
{
if (_placedStories.ContainsKey(story)) return; // Don't place already placed stories, idiot!
_placedStories[story] = null; // Avoids potential for infinite loops when evaluating constraints
var contentTags = GetContentTags(story);
public void ProcessQuest(Story story)
{
var quest = new GalaxyQuest();
quest.Story = story;
foreach (var knot in _storyKnotPaths[story])
{
var tags = GetContentTags(story.TagsForContentAtPath(knot));
}
}
public void ProcessLocation(Story story, FileInfo inkFile)
{
if (_storyLocations.ContainsKey(story)) return; // Don't place already placed stories, idiot!
_storyLocations[story] = null; // Avoids potential for infinite loops when evaluating constraints
var fileName = Path.GetFileNameWithoutExtension(inkFile.FullName);
var contentTags = GetContentTags(story.globalTags);
var constraints = new List<ZoneConstraint>();
if(contentTags.ContainsKey("constraint"))
@ -157,16 +177,34 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
else
selector = new RandomSelector(ref _random);
var zoneCandidates = new List<SectorZone>();
zoneCandidates.AddRange(Sector.Zones.Where(z=>constraints.All(c=>c.Test(z))));
_placedStories[story] = selector.SelectZone(zoneCandidates);
var zoneCandidates = new List<GalaxyZone>();
zoneCandidates.AddRange(Galaxy.Zones.Where(z=>!z.NamedZone && constraints.All(c=>c.Test(z))));
var zone = selector.SelectZone(zoneCandidates);
var location = new LocationStory
{
FileName = fileName,
Name = contentTags.ContainsKey("name") ? contentTags["name"].First() : fileName,
Faction = contentTags.ContainsKey("faction") ? ResolveFaction(contentTags["faction"].First()) : zone.Owner,
Security = contentTags.ContainsKey("security")
? (SecurityLevel) Enum.Parse(typeof(SecurityLevel), contentTags["security"].First(), true)
: SecurityLevel.Open,
Story = story,
Type = contentTags.ContainsKey("type")
? (LocationType) Enum.Parse(typeof(LocationType), contentTags["type"].First(), true)
: LocationType.Station
};
zone.Locations.Add(location);
_storyLocations[story] = zone;
}
// Parse all tags of the format X:Y into a dictionary with a list of every Y for each X
public static Dictionary<string, List<string>> GetContentTags(Story story)
public static Dictionary<string, List<string>> GetContentTags(List<string> tags)
{
var contentTags = new Dictionary<string, List<string>>();
foreach (var tag in story.globalTags)
foreach (var tag in tags)
{
if (tag.IndexOf(':') == -1) continue;

View file

@ -4,7 +4,7 @@ using System.Linq;
public interface IZoneResolver
{
public SectorZone ResolveZone(string path);
public GalaxyZone ResolveZone(string path);
}
public interface IFactionResolver
@ -16,12 +16,12 @@ public abstract class ZoneConstraint
{
public bool Flip = false;
public bool Test(SectorZone zone)
public bool Test(GalaxyZone zone)
{
return Flip ^ TestZone(zone);
}
protected abstract bool TestZone(SectorZone zone);
protected abstract bool TestZone(GalaxyZone zone);
}
public class FactionPresenceConstraint : ZoneConstraint
@ -32,7 +32,7 @@ public class FactionPresenceConstraint : ZoneConstraint
TargetFaction = resolver.ResolveFaction(args[0]);
}
protected override bool TestZone(SectorZone zone)
protected override bool TestZone(GalaxyZone zone)
{
return zone.Factions.Any(f=>f.ID == TargetFaction?.ID);
}
@ -47,7 +47,7 @@ public class FactionOwnerConstraint : ZoneConstraint
TargetFaction = resolver.ResolveFaction(args[0]);
}
protected override bool TestZone(SectorZone zone)
protected override bool TestZone(GalaxyZone zone)
{
return zone.Owner.ID == TargetFaction?.ID;
}
@ -55,7 +55,7 @@ public class FactionOwnerConstraint : ZoneConstraint
public class DistanceConstraint : ZoneConstraint
{
private SectorZone _targetZone;
private GalaxyZone _targetZone;
private Predicate<int> _test;
public DistanceConstraint(string[] args, IZoneResolver zoneResolver)
@ -82,7 +82,7 @@ public class DistanceConstraint : ZoneConstraint
}
}
protected override bool TestZone(SectorZone zone)
protected override bool TestZone(GalaxyZone zone)
{
return _targetZone != null && _test(zone.Distance[_targetZone]);
}

View file

@ -6,16 +6,16 @@ using Random = Unity.Mathematics.Random;
public abstract class ZoneSelector
{
public abstract SectorZone SelectZone(List<SectorZone> candidates);
public abstract GalaxyZone SelectZone(List<GalaxyZone> candidates);
}
public abstract class OrderedZoneSelector : ZoneSelector
{
public bool Flip = false;
protected abstract Func<SectorZone, IComparable> Comparison { get; }
protected abstract Func<GalaxyZone, IComparable> Comparison { get; }
public override SectorZone SelectZone(List<SectorZone> candidates)
public override GalaxyZone SelectZone(List<GalaxyZone> candidates)
{
var sorted = candidates.OrderBy(Comparison);
return Flip ? sorted.Last() : sorted.First();
@ -24,7 +24,7 @@ public abstract class OrderedZoneSelector : ZoneSelector
public class DistanceSelector : OrderedZoneSelector
{
private SectorZone Target { get; }
private GalaxyZone Target { get; }
public DistanceSelector(string[] args, IZoneResolver zoneResolver)
@ -32,7 +32,7 @@ public class DistanceSelector : OrderedZoneSelector
Target = zoneResolver.ResolveZone(args[0].Trim());
}
protected override Func<SectorZone, IComparable> Comparison => zone => Target?.Distance[zone] ?? 0;
protected override Func<GalaxyZone, IComparable> Comparison => zone => Target?.Distance[zone] ?? 0;
}
public class RandomSelector : ZoneSelector
@ -44,7 +44,7 @@ public class RandomSelector : ZoneSelector
Random = random;
}
public override SectorZone SelectZone(List<SectorZone> candidates)
public override GalaxyZone SelectZone(List<GalaxyZone> candidates)
{
return candidates[Random.NextInt(candidates.Count)];
}

View file

@ -37,7 +37,7 @@ public class OrbitalEntity : Entity
{
if (SecurityRadius < 1) return false;
if (Faction == null) return false;
return !IsPresencePermitted(Zone.Sector.FactionRelationships[Faction], SecurityLevel);
return !IsPresencePermitted(Zone.Galaxy.FactionRelationships[Faction], SecurityLevel);
}
}
}

View file

@ -49,35 +49,35 @@ public class SavedGame
public SavedGame() { }
public SavedGame(Sector sector, Zone currentZone, Entity currentEntity)
public SavedGame(Galaxy galaxy, Zone currentZone, Entity currentEntity)
{
DiscoveredZones = sector.DiscoveredZones.Select(dz => Array.IndexOf(sector.Zones, dz)).ToArray();
Background = sector.Background;
Factions = sector.HomeZones.Keys.Select(f => f.ID).ToArray();
Relationships = sector.Factions.Select(f => sector.FactionRelationships[f]).ToArray();
DiscoveredZones = galaxy.DiscoveredZones.Select(dz => Array.IndexOf(galaxy.Zones, dz)).ToArray();
Background = galaxy.Background;
Factions = galaxy.HomeZones.Keys.Select(f => f.ID).ToArray();
Relationships = galaxy.Factions.Select(f => galaxy.FactionRelationships[f]).ToArray();
HomeZones = sector.HomeZones.ToDictionary(
HomeZones = galaxy.HomeZones.ToDictionary(
x => Array.IndexOf(Factions, x.Key.ID),
x => Array.IndexOf(sector.Zones, x.Value));
BossZones = sector.BossZones.ToDictionary(
x => Array.IndexOf(galaxy.Zones, x.Value));
BossZones = galaxy.BossZones.ToDictionary(
x => Array.IndexOf(Factions, x.Key.ID),
x => Array.IndexOf(sector.Zones, x.Value));
x => Array.IndexOf(galaxy.Zones, x.Value));
Zones = sector.Zones.Select(zone => new SavedZone
Zones = galaxy.Zones.Select(zone => new SavedZone
{
Name = zone.Name,
Position = zone.Position,
AdjacentZones = zone.AdjacentZones.Select(az=> Array.IndexOf(sector.Zones, az)).ToArray(),
AdjacentZones = zone.AdjacentZones.Select(az=> Array.IndexOf(galaxy.Zones, az)).ToArray(),
Factions = zone.Factions.Select(f=> Array.IndexOf(Factions, f.ID)).ToArray(),
Contents = zone.Contents?.PackZone(),
Owner = zone.Owner == null ? -1 : Array.IndexOf(Factions, zone.Owner.ID)
}).ToArray();
CurrentZone = Array.FindIndex(sector.Zones, zone => zone.Contents == currentZone);
CurrentZone = Array.FindIndex(galaxy.Zones, zone => zone.Contents == currentZone);
CurrentZoneEntity = currentZone.Entities.IndexOf(currentEntity);
Entrance = Array.IndexOf(sector.Zones, sector.Entrance);
Exit = Array.IndexOf(sector.Zones, sector.Exit);
Entrance = Array.IndexOf(galaxy.Zones, galaxy.Entrance);
Exit = Array.IndexOf(galaxy.Zones, galaxy.Exit);
}
}

View file

@ -46,6 +46,7 @@ public class Ship : Entity
private float2 _wormholePosition;
private float2 _wormholeExitVelocity;
public bool WormholeAnimationInProgress => _enteringWormhole || _exitingWormhole;
public float ForwardThrust { get; private set; }
public float ReverseThrust { get; private set; }
public float LeftStrafeThrust { get; private set; }

View file

@ -3,5 +3,5 @@ using Unity.Mathematics;
public class Wormhole
{
public float2 Position;
public SectorZone Target;
public GalaxyZone Target;
}

View file

@ -41,18 +41,18 @@ public class Zone
get => (float) _time;
}
public ZonePack Pack { get; }
public SectorZone SectorZone { get; }
public Sector Sector { get; }
public GalaxyZone GalaxyZone { get; }
public Galaxy Galaxy { get; }
public Zone(ItemManager itemManager, PlanetSettings settings, ZonePack pack, SectorZone sectorZone, Sector sector)
public Zone(ItemManager itemManager, PlanetSettings settings, ZonePack pack, GalaxyZone galaxyZone, Galaxy galaxy)
{
_time = pack.Time;
SectorZone = sectorZone;
Sector = sector;
GalaxyZone = galaxyZone;
Galaxy = galaxy;
Pack = pack;
_itemManager = itemManager;
Settings = settings;
_random = new Random(Convert.ToUInt32(abs(sectorZone?.Name.GetHashCode() ?? 1337)));
_random = new Random(Convert.ToUInt32(abs(galaxyZone?.Name.GetHashCode() ?? 1337)));
foreach (var orbit in pack.Orbits)
{
@ -311,12 +311,12 @@ public class Zone
public SecurityLevel GetSecurityLevel(float2 pos)
{
if (SectorZone.Owner==null) return SecurityLevel.Open;
if (GalaxyZone.Owner==null) return SecurityLevel.Open;
var security = SecurityLevel.Open;
foreach (var entity in Entities)
{
if (entity is OrbitalEntity orbitalEntity && orbitalEntity.SecurityRadius > 1 && entity.Faction.ID == SectorZone.Owner.ID)
if (entity is OrbitalEntity orbitalEntity && orbitalEntity.SecurityRadius > 1 && entity.Faction.ID == GalaxyZone.Owner.ID)
{
if (orbitalEntity.SecurityLevel > security && length(orbitalEntity.Position.xz - pos) < orbitalEntity.SecurityRadius * Settings.SecureAreaRadiusMultiplier)
security = orbitalEntity.SecurityLevel;

View file

@ -38,15 +38,15 @@ public static class ZoneGenerator
public static ZonePack GenerateZone(
ItemManager itemManager,
ZoneGenerationSettings zoneSettings,
Sector sector,
SectorZone sectorZone,
Galaxy galaxy,
GalaxyZone galaxyZone,
bool isTutorial = false)
{
var pack = new ZonePack();
var random = new Random(unchecked((uint) sectorZone.Name.GetHashCode()) ^ hash(sectorZone.Position));
var random = new Random(unchecked((uint) galaxyZone.Name.GetHashCode()) ^ hash(galaxyZone.Position));
var density = saturate(sector.Background.CloudDensity(sectorZone.Position)/2);
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);
@ -222,9 +222,9 @@ public static class ZoneGenerator
return planetData;
}).ToList();
var nearestFaction = sector.Factions.MinBy(f => sector.HomeZones[f].Distance[sectorZone]);
var nearestFactionHomeZone = sector.HomeZones[nearestFaction];
var factionPresence = nearestFaction.InfluenceDistance - nearestFactionHomeZone.Distance[sectorZone] + 1;
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 stationCount = (int)(random.NextFloat() * (factionPresence + 1));
var potentialLagrangePoints = planets
@ -240,7 +240,7 @@ public static class ZoneGenerator
.ToArray();
var loadoutGenerator = isTutorial ? new LoadoutGenerator(ref random, itemManager, nearestFaction, .5f) :
new LoadoutGenerator(ref random, itemManager, sector, sectorZone, nearestFaction, .5f);
new LoadoutGenerator(ref random, itemManager, galaxy, galaxyZone, nearestFaction, .5f);
foreach (var orbit in selectedStationOrbits)
{