Multi-Location Quest Injection
This commit is contained in:
parent
2f98904614
commit
b0673c82fc
23 changed files with 279 additions and 105 deletions
|
|
@ -86,7 +86,7 @@ Material:
|
|||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _Scale: 1.6706811
|
||||
- _Scale: 0.5
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ MonoBehaviour:
|
|||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColor: {r: 0.6981132, g: 0.6981132, b: 0.6981132, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
|
|
@ -148,7 +148,7 @@ MonoBehaviour:
|
|||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 1
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 256
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
|
|
|
|||
|
|
@ -22583,7 +22583,7 @@ GameObject:
|
|||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1485884352
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -23721,7 +23721,7 @@ PrefabInstance:
|
|||
- target: {fileID: 878382121558056004, guid: 2758dfa2744d7ad4d8877545189d116e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
value: 55.675
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 878382121558056004, guid: 2758dfa2744d7ad4d8877545189d116e,
|
||||
type: 3}
|
||||
|
|
@ -24933,7 +24933,7 @@ PrefabInstance:
|
|||
- target: {fileID: 878382121558056004, guid: 2758dfa2744d7ad4d8877545189d116e,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
value: 60.98
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 878382121558056004, guid: 2758dfa2744d7ad4d8877545189d116e,
|
||||
type: 3}
|
||||
|
|
|
|||
|
|
@ -234,7 +234,6 @@ public class ActionGameManager : MonoBehaviour
|
|||
public ItemManager ItemManager { get; private set; }
|
||||
public Zone Zone { get; private set; }
|
||||
public List<EntityPack> Loadouts { get; } = new List<EntityPack>();
|
||||
public IEnumerable<Story> GetStories => _stories;
|
||||
|
||||
private readonly (float2 direction, string name)[] _directions = {
|
||||
(float2(0, 1), "Front"),
|
||||
|
|
@ -488,7 +487,7 @@ public class ActionGameManager : MonoBehaviour
|
|||
return slot;
|
||||
}
|
||||
|
||||
foreach (var actionBarInput in PlayerSettings.InputSettings.ActionBarInputs) createBinding(actionBarInput);
|
||||
foreach (var actionBarInput in PlayerSettings.InputSettings.ActionBarInputs.OrderBy(i=>i)) createBinding(actionBarInput);
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ public abstract class Entity
|
|||
|
||||
public string Name;
|
||||
|
||||
public int Population;
|
||||
public Dictionary<Guid, float> Personality = new Dictionary<Guid, float>();
|
||||
// public int Population;
|
||||
// public Dictionary<Guid, float> Personality = new Dictionary<Guid, float>();
|
||||
|
||||
public readonly Dictionary<string, float> Messages = new Dictionary<string, float>();
|
||||
public readonly Dictionary<object, float> VisibilitySources = new Dictionary<object, float>();
|
||||
|
|
@ -288,7 +288,7 @@ 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.GalaxyZone.Owner.ID)
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ public static class EntitySerializer
|
|||
Restore(itemManager, zone, pack, entity, instantiate);
|
||||
entity.SecurityLevel = pack.SecurityLevel;
|
||||
entity.SecurityRadius = pack.SecurityRadius;
|
||||
if (pack.Story >= 0) entity.Story = zone.GalaxyZone.Locations[pack.Story];
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +167,7 @@ public class ShipPack : EntityPack
|
|||
public class OrbitalEntityPack : EntityPack
|
||||
{
|
||||
[Key(17)] public Guid Orbit;
|
||||
[Key(18)] public SavedStory Story;
|
||||
[Key(18)] public int Story = -1;
|
||||
[Key(19)] public SecurityLevel SecurityLevel;
|
||||
[Key(20)] public float SecurityRadius;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ public enum CompoundCommodityCategory
|
|||
public enum LocationType
|
||||
{
|
||||
Station,
|
||||
Asteroid,
|
||||
Planet
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ public class Galaxy
|
|||
public GalaxyZone Entrance { get; }
|
||||
public GalaxyZone Exit { get; }
|
||||
public Dictionary<Faction, FactionRelationship> FactionRelationships { get; } = new Dictionary<Faction, FactionRelationship>();
|
||||
private Action<string> Log { get; }
|
||||
|
||||
private HashSet<Guid> _containedFactions;
|
||||
private GalaxyZone[] _exitPath;
|
||||
|
|
@ -41,8 +42,9 @@ public class Galaxy
|
|||
}
|
||||
}
|
||||
|
||||
public Galaxy(CultCache cultCache, SavedGame savedGame)
|
||||
public Galaxy(CultCache cultCache, SavedGame savedGame, Action<string> log)
|
||||
{
|
||||
Log = log;
|
||||
Background = savedGame.Background;
|
||||
|
||||
Factions = savedGame.Factions.Select(cultCache.Get<Faction>).ToArray();
|
||||
|
|
@ -87,11 +89,13 @@ public class Galaxy
|
|||
SectorGenerationSettings settings,
|
||||
SectorBackgroundSettings background,
|
||||
NameGeneratorSettings nameGeneratorSettings,
|
||||
CultCache cache,
|
||||
CultCache cache,
|
||||
Action<string> log,
|
||||
Action<string> progressCallback = null,
|
||||
uint seed = 0)
|
||||
{
|
||||
Background = background;
|
||||
Log = log;
|
||||
var factions = cache.GetAll<Faction>();
|
||||
var random = new Random(seed == 0 ? (uint) (DateTime.Now.Ticks % uint.MaxValue) : seed);
|
||||
Factions = factions.OrderBy(x => random.NextFloat()).Take(settings.MegaCount).ToArray();
|
||||
|
|
@ -129,12 +133,14 @@ public class Galaxy
|
|||
CultCache cache,
|
||||
PlayerSettings playerSettings,
|
||||
DirectoryInfo narrativeDirectory,
|
||||
Action<string> log,
|
||||
Action<string> progressCallback = null,
|
||||
uint seed = 0)
|
||||
{
|
||||
Faction ResolveFaction(string name) => cache.GetAll<Faction>().FirstOrDefault(f => f.Name.StartsWith(name, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
Background = background;
|
||||
Log = log;
|
||||
var random = new Random(seed == 0 ? (uint) (DateTime.Now.Ticks % uint.MaxValue) : seed);
|
||||
|
||||
var factions = new List<Faction>();
|
||||
|
|
@ -219,12 +225,8 @@ public class Galaxy
|
|||
GenerateNames(cache, nameGeneratorSettings, ref random, progressCallback);
|
||||
|
||||
progressCallback?.Invoke("Weaving Narrative");
|
||||
// var processor = new StoryProcessor(playerSettings, narrativeDirectory, this, ref random);
|
||||
// var storyPlacement = processor.PlaceStories();
|
||||
// foreach (var story in storyPlacement.Keys)
|
||||
// {
|
||||
// storyPlacement[story]
|
||||
// }
|
||||
var processor = new StoryProcessor(playerSettings, narrativeDirectory, this, ref random, Log);
|
||||
processor.ProcessStories();
|
||||
|
||||
progressCallback?.Invoke("Done!");
|
||||
if(progressCallback!=null) Thread.Sleep(500); // Inserting Delay to make it seem like it's doing more work lmao
|
||||
|
|
@ -554,15 +556,18 @@ public class GalaxyZone
|
|||
public class GalaxyQuest
|
||||
{
|
||||
public Story Story;
|
||||
public Dictionary<string, LocationStory> Locations = new Dictionary<string, LocationStory>();
|
||||
public Dictionary<string, LocationStory> KnotLocations = new Dictionary<string, LocationStory>();
|
||||
}
|
||||
|
||||
public class LocationStory
|
||||
{
|
||||
public GalaxyZone Zone;
|
||||
public string FileName;
|
||||
public string Name;
|
||||
public Story Story;
|
||||
public Faction Faction;
|
||||
public SecurityLevel Security;
|
||||
public LocationType Type;
|
||||
public int Turrets;
|
||||
public Dictionary<string, List<GalaxyQuest>> KnotQuests = new Dictionary<string, List<GalaxyQuest>>();
|
||||
}
|
||||
|
|
@ -26,22 +26,24 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
|
|||
}
|
||||
|
||||
private Dictionary<Story, string[]> _storyKnotPaths = new Dictionary<Story, string[]>();
|
||||
private Dictionary<Story, GalaxyZone> _storyLocations = new Dictionary<Story, GalaxyZone>();
|
||||
private Dictionary<Story, LocationStory> _placedStories = new Dictionary<Story, LocationStory>();
|
||||
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 Galaxy Galaxy { get; }
|
||||
public PlayerSettings Settings { get; }
|
||||
|
||||
private Action<string> Log { get; }
|
||||
|
||||
public StoryProcessor(PlayerSettings settings, DirectoryInfo narrativeDirectory, Galaxy galaxy, ref Random random)
|
||||
public StoryProcessor(PlayerSettings settings, DirectoryInfo narrativeDirectory, Galaxy galaxy, ref Random random, Action<string> log)
|
||||
{
|
||||
NarrativeDirectory = narrativeDirectory;
|
||||
Galaxy = galaxy;
|
||||
_random = random;
|
||||
Log = log;
|
||||
Settings = settings;
|
||||
|
||||
_inkFileHandler = new AetheriaInkFileHandler(narrativeDirectory);
|
||||
|
|
@ -56,7 +58,7 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
|
|||
foreach(var inkFile in locationFiles) ProcessLocation(GetStory(inkFile), inkFile);
|
||||
|
||||
var questFiles = _questsPath.EnumerateFiles("*ink");
|
||||
foreach(var inkFile in questFiles) ProcessQuest(GetStory(inkFile));
|
||||
foreach(var inkFile in questFiles) ProcessQuest(GetStory(inkFile), inkFile);
|
||||
}
|
||||
|
||||
public GalaxyZone ResolveZone(string path)
|
||||
|
|
@ -74,13 +76,18 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
|
|||
var faction = ResolveFaction(factionString);
|
||||
return !Galaxy.HomeZones.ContainsKey(faction) ? null : Galaxy.HomeZones[faction];
|
||||
}
|
||||
|
||||
|
||||
return ResolveLocation(path)?.Zone;
|
||||
}
|
||||
|
||||
public LocationStory ResolveLocation(string path)
|
||||
{
|
||||
var locationInkFile = new FileInfo(Path.Combine(_locationsPath.FullName, $"{path}.ink"));
|
||||
if (!locationInkFile.Exists) return null;
|
||||
|
||||
var story = GetStory(locationInkFile);
|
||||
ProcessLocation(story, locationInkFile);
|
||||
return _storyLocations.ContainsKey(story) ? _storyLocations[story] : null;
|
||||
return _placedStories.ContainsKey(story) ? _placedStories[story] : null;
|
||||
}
|
||||
|
||||
public Faction ResolveFaction(string name)
|
||||
|
|
@ -95,20 +102,20 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
|
|||
// If the story has already been read / compiled, return it directly
|
||||
if (_processedStories.ContainsKey(fileName)) return _processedStories[fileName];
|
||||
|
||||
var compiledFileName = Path.Combine(inkFile.Directory.FullName, $"{fileName}.json");
|
||||
|
||||
// Calculate a hash of the ink file
|
||||
var hash = File.ReadAllBytes(inkFile.FullName).GetHashSHA1();
|
||||
|
||||
if (File.Exists(compiledFileName) && // If a compiled version of the ink file exists
|
||||
Settings.HashedStoryFiles.ContainsKey(fileName) && // And its hash has been saved
|
||||
hash == Settings.HashedStoryFiles[fileName]) // And the saved hash matches the current hash
|
||||
{
|
||||
// Load the story from the existing compiled JSON representation
|
||||
return new Story(File.ReadAllText(compiledFileName));
|
||||
}
|
||||
|
||||
Settings.HashedStoryFiles[fileName] = hash;
|
||||
// var compiledFileName = Path.Combine(inkFile.Directory.FullName, $"{fileName}.json");
|
||||
//
|
||||
// // Calculate a hash of the ink file
|
||||
// var hash = File.ReadAllBytes(inkFile.FullName).GetHashSHA1();
|
||||
//
|
||||
// if (File.Exists(compiledFileName) && // If a compiled version of the ink file exists
|
||||
// Settings.HashedStoryFiles.ContainsKey(fileName) && // And its hash has been saved
|
||||
// hash == Settings.HashedStoryFiles[fileName]) // And the saved hash matches the current hash
|
||||
// {
|
||||
// // Load the story from the existing compiled JSON representation
|
||||
// return new Story(File.ReadAllText(compiledFileName));
|
||||
// }
|
||||
//
|
||||
// Settings.HashedStoryFiles[fileName] = hash;
|
||||
var compiler = new Compiler(File.ReadAllText(inkFile.FullName), new Compiler.Options
|
||||
{
|
||||
countAllVisits = true,
|
||||
|
|
@ -117,25 +124,45 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
|
|||
var story = compiler.Compile();
|
||||
var knots = compiler.parsedStory.FindAll<Knot>().Select(k=>k.runtimePath.ToString()).ToArray();
|
||||
_storyKnotPaths[story] = knots;
|
||||
File.WriteAllText(compiledFileName, story.ToJson());
|
||||
//File.WriteAllText(compiledFileName, story.ToJson());
|
||||
_processedStories[fileName] = story;
|
||||
return story;
|
||||
}
|
||||
|
||||
public void ProcessQuest(Story story)
|
||||
public void ProcessQuest(Story story, FileInfo inkFile)
|
||||
{
|
||||
var fileName = Path.GetFileNameWithoutExtension(inkFile.FullName);
|
||||
var quest = new GalaxyQuest();
|
||||
quest.Story = story;
|
||||
foreach (var knot in _storyKnotPaths[story])
|
||||
{
|
||||
var tags = GetContentTags(story.TagsForContentAtPath(knot));
|
||||
|
||||
var tags = story.TagsForContentAtPath(knot);
|
||||
if(tags==null) continue;
|
||||
var contentTags = GetContentTags(tags);
|
||||
if (contentTags.ContainsKey("location"))
|
||||
{
|
||||
var locationName = contentTags["location"].First();
|
||||
var locationStory = ResolveLocation(locationName);
|
||||
if (tags.Contains("required") && locationStory == null)
|
||||
{
|
||||
Log($"Quest \"{fileName}\" unable to find required location \"{locationName}\" for knot \"{knot}\"");
|
||||
return;
|
||||
}
|
||||
quest.KnotLocations[knot] = locationStory;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var x in quest.KnotLocations)
|
||||
{
|
||||
if (!x.Value.KnotQuests.ContainsKey(x.Key)) x.Value.KnotQuests[x.Key] = new List<GalaxyQuest>();
|
||||
x.Value.KnotQuests[x.Key].Add(quest);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
if (_placedStories.ContainsKey(story)) return; // Don't place already placed stories, idiot!
|
||||
_placedStories[story] = null; // Avoids potential for infinite loops when evaluating constraints
|
||||
var fileName = Path.GetFileNameWithoutExtension(inkFile.FullName);
|
||||
|
||||
var contentTags = GetContentTags(story.globalTags);
|
||||
|
|
@ -184,6 +211,7 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
|
|||
|
||||
var location = new LocationStory
|
||||
{
|
||||
Zone = zone,
|
||||
FileName = fileName,
|
||||
Name = contentTags.ContainsKey("name") ? contentTags["name"].First() : fileName,
|
||||
Faction = contentTags.ContainsKey("faction") ? ResolveFaction(contentTags["faction"].First()) : zone.Owner,
|
||||
|
|
@ -193,11 +221,17 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
|
|||
Story = story,
|
||||
Type = contentTags.ContainsKey("type")
|
||||
? (LocationType) Enum.Parse(typeof(LocationType), contentTags["type"].First(), true)
|
||||
: LocationType.Station
|
||||
: LocationType.Station,
|
||||
Turrets = contentTags.ContainsKey("turrets") ? int.Parse(contentTags["turrets"].First()) : 0
|
||||
};
|
||||
zone.Locations.Add(location);
|
||||
|
||||
_storyLocations[story] = zone;
|
||||
if (contentTags.ContainsKey("namezone"))
|
||||
{
|
||||
zone.Name = contentTags["namezone"].First();
|
||||
}
|
||||
|
||||
_placedStories[story] = location;
|
||||
}
|
||||
|
||||
// Parse all tags of the format X:Y into a dictionary with a list of every Y for each X
|
||||
|
|
@ -209,7 +243,7 @@ public class StoryProcessor : IZoneResolver, IFactionResolver
|
|||
if (tag.IndexOf(':') == -1) continue;
|
||||
|
||||
var tokens = tag.Split(':');
|
||||
var leftSide = tokens[0].Trim();
|
||||
var leftSide = tokens[0].Trim().ToLowerInvariant();
|
||||
var rightSide = tokens[1].Trim();
|
||||
if (!contentTags.ContainsKey(leftSide)) contentTags[leftSide] = new List<string>();
|
||||
contentTags[leftSide].Add(rightSide);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public class OrbitalEntity : Entity
|
|||
public Guid OrbitData;
|
||||
public SecurityLevel SecurityLevel;
|
||||
public float SecurityRadius;
|
||||
public LocationStory Story;
|
||||
|
||||
public OrbitalEntity(ItemManager itemManager, Zone zone, EquippableItem hull, Guid orbit, EntitySettings settings) : base(itemManager, zone, hull, settings)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -226,7 +226,8 @@ public static class ZoneGenerator
|
|||
var nearestFactionHomeZone = galaxy.HomeZones[nearestFaction];
|
||||
var factionPresence = nearestFaction.InfluenceDistance - nearestFactionHomeZone.Distance[galaxyZone] + 1;
|
||||
|
||||
var stationCount = (int)(random.NextFloat() * (factionPresence + 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
|
||||
|
|
@ -238,59 +239,92 @@ public static class ZoneGenerator
|
|||
.Take(stationCount)
|
||||
.Select(p=>orbitMap[p])
|
||||
.ToArray();
|
||||
|
||||
var loadoutGenerator = isTutorial ? new LoadoutGenerator(ref random, itemManager, nearestFaction, .5f) :
|
||||
new LoadoutGenerator(ref random, itemManager, galaxy, galaxyZone, nearestFaction, .5f);
|
||||
|
||||
foreach (var orbit in selectedStationOrbits)
|
||||
|
||||
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 security = (SecurityLevel) ((int) ((1f - pow(random.NextFloat(), factionPresence / 2f)) * 3f));
|
||||
var lagrangeOrbit = new OrbitData
|
||||
{
|
||||
ID = Guid.NewGuid(),
|
||||
Parent = orbit.Parent,
|
||||
Distance = new ReactiveProperty<float>(orbit.Distance.Value),
|
||||
Phase = orbit.Phase + PI / 3 * sign(random.NextFloat() - .5f)
|
||||
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 station = loadoutGenerator.GenerateStationLoadout();
|
||||
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 * .75f;
|
||||
station.SecurityRadius = pack.Radius;
|
||||
pack.Entities.Add(station);
|
||||
|
||||
var turretPhase = 20f / lagrangeOrbit.Distance.Value;
|
||||
|
||||
var leadingTurretOrbit = new OrbitData
|
||||
{
|
||||
ID = Guid.NewGuid(),
|
||||
Parent = orbit.Parent,
|
||||
Distance = new ReactiveProperty<float>(orbit.Distance.Value),
|
||||
Phase = lagrangeOrbit.Phase + turretPhase
|
||||
};
|
||||
pack.Orbits.Add(leadingTurretOrbit);
|
||||
var leadingTurret = loadoutGenerator.GenerateTurretLoadout();
|
||||
leadingTurret.Orbit = leadingTurretOrbit.ID;
|
||||
pack.Entities.Add(leadingTurret);
|
||||
|
||||
var trailingTurretOrbit = new OrbitData
|
||||
{
|
||||
ID = Guid.NewGuid(),
|
||||
Parent = orbit.Parent,
|
||||
Distance = new ReactiveProperty<float>(orbit.Distance.Value),
|
||||
Phase = lagrangeOrbit.Phase - turretPhase
|
||||
};
|
||||
pack.Orbits.Add(trailingTurretOrbit);
|
||||
var trailingTurret = loadoutGenerator.GenerateTurretLoadout();
|
||||
trailingTurret.Orbit = trailingTurretOrbit.ID;
|
||||
pack.Entities.Add(trailingTurret);
|
||||
|
||||
PlaceTurrets(lagrangeOrbit, GetLoadoutGenerator(nearestFaction), 2);
|
||||
}
|
||||
|
||||
|
||||
var enemyCount = (int)(random.NextFloat() * factionPresence * 2) + stationCount;
|
||||
for (int i = 0; i < enemyCount; i++)
|
||||
{
|
||||
pack.Entities.Add(loadoutGenerator.GenerateShipLoadout());
|
||||
pack.Entities.Add(GetLoadoutGenerator(nearestFaction).GenerateShipLoadout());
|
||||
}
|
||||
|
||||
return pack;
|
||||
|
|
|
|||
|
|
@ -100,7 +100,8 @@ public class MainMenu : MonoBehaviour
|
|||
ActionGameManager.IsTutorial = ActionGameManager.PlayerSettings.SavedRun.IsTutorial;
|
||||
ActionGameManager.CurrentGalaxy = new Galaxy(
|
||||
ActionGameManager.CultCache,
|
||||
ActionGameManager.PlayerSettings.SavedRun);
|
||||
ActionGameManager.PlayerSettings.SavedRun,
|
||||
Debug.Log);
|
||||
SceneManager.LoadScene("ARPG");
|
||||
});
|
||||
else
|
||||
|
|
@ -130,6 +131,7 @@ public class MainMenu : MonoBehaviour
|
|||
Settings.SectorBackgroundSettings,
|
||||
Settings.NameGeneratorSettings,
|
||||
ActionGameManager.CultCache,
|
||||
Debug.Log,
|
||||
setState);
|
||||
Observable.NextFrame().Subscribe(_ =>
|
||||
{
|
||||
|
|
@ -158,6 +160,7 @@ public class MainMenu : MonoBehaviour
|
|||
ActionGameManager.CultCache,
|
||||
ActionGameManager.PlayerSettings,
|
||||
ActionGameManager.GameDataDirectory.CreateSubdirectory("Narrative"),
|
||||
Debug.Log,
|
||||
setState);
|
||||
Observable.NextFrame().Subscribe(_ =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,13 +14,20 @@ public class LocalMenu : MonoBehaviour
|
|||
public TextMeshProUGUI Output;
|
||||
public RectTransform ChoiceParent;
|
||||
public ChoicePrefab ChoicePrefab;
|
||||
|
||||
private Story _currentStory;
|
||||
|
||||
private string _currentPath;
|
||||
private LocationStory _currentLocation;
|
||||
private Story _activeStory;
|
||||
private List<GameObject> _choiceInstances = new List<GameObject>();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_currentStory = ActionGameManager.Instance.GetStories.First();
|
||||
if (ActionGameManager.Instance.DockedEntity is OrbitalEntity orbital)
|
||||
{
|
||||
_currentLocation = orbital.Story;
|
||||
_activeStory = _currentLocation.Story;
|
||||
}
|
||||
else return;
|
||||
Continue();
|
||||
}
|
||||
|
||||
|
|
@ -28,31 +35,72 @@ public class LocalMenu : MonoBehaviour
|
|||
{
|
||||
ContinueTrigger.OnPointerClickAsObservable().Subscribe(pointerEvent =>
|
||||
{
|
||||
if (_currentStory == null) return;
|
||||
|
||||
if(_currentStory.canContinue) Continue();
|
||||
if (_activeStory == null) return;
|
||||
Continue();
|
||||
});
|
||||
}
|
||||
|
||||
void Continue()
|
||||
{
|
||||
Output.text = _currentStory.Continue();
|
||||
if (!_activeStory.state.previousPointer.isNull) _currentPath = _activeStory.state.previousPointer.path.head.name;
|
||||
if(_activeStory.canContinue) _activeStory.Continue();
|
||||
if (!_activeStory.state.previousPointer.isNull) _currentPath = _activeStory.state.previousPointer.path.head.name;
|
||||
Output.text = _activeStory.currentText;
|
||||
|
||||
foreach(var instance in _choiceInstances)
|
||||
Destroy(instance);
|
||||
_choiceInstances.Clear();
|
||||
|
||||
foreach (var choice in _currentStory.currentChoices)
|
||||
if(_activeStory.currentChoices.Any())
|
||||
{
|
||||
var choiceInstance = Instantiate(ChoicePrefab, ChoiceParent);
|
||||
choiceInstance.Label.text = choice.text;
|
||||
choiceInstance.Button.onClick.AddListener(() =>
|
||||
{
|
||||
_currentStory.ChoosePath(choice.targetPath);
|
||||
Continue();
|
||||
});
|
||||
_choiceInstances.Add(choiceInstance.gameObject);
|
||||
PresentCurrentChoices();
|
||||
}
|
||||
else if (!_activeStory.canContinue)
|
||||
{
|
||||
// There's no choices, but we also can't continue; indicates we hit an END
|
||||
if (_activeStory == _currentLocation.Story)
|
||||
{
|
||||
// END inside location-based story thread, restart the story
|
||||
_activeStory.ResetState();
|
||||
Continue();
|
||||
}
|
||||
else
|
||||
{
|
||||
// END inside quest content, switch back to location thread and present choices
|
||||
_activeStory = _currentLocation.Story;
|
||||
Continue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PresentCurrentChoices()
|
||||
{
|
||||
Debug.Log($"Current Path: \"{_currentPath}\" in {(_activeStory == _currentLocation.Story ? "Location Story" : "Quest Story")}");
|
||||
if(!string.IsNullOrEmpty(_currentPath) && _currentLocation.KnotQuests.ContainsKey(_currentPath))
|
||||
{
|
||||
foreach (var quest in _currentLocation.KnotQuests[_currentPath])
|
||||
{
|
||||
if (quest.Story == _activeStory) continue; // Don't repeat choices for active injected branch
|
||||
|
||||
quest.Story.ChoosePathString(_currentPath);
|
||||
quest.Story.ContinueMaximally();
|
||||
foreach (var choice in quest.Story.currentChoices) PresentChoice(quest.Story, choice);
|
||||
}
|
||||
}
|
||||
foreach (var choice in _activeStory.currentChoices) PresentChoice(_activeStory, choice);
|
||||
}
|
||||
|
||||
void PresentChoice(Story story, Choice choice)
|
||||
{
|
||||
var choiceInstance = Instantiate(ChoicePrefab, ChoiceParent);
|
||||
choiceInstance.Label.text = choice.text;
|
||||
choiceInstance.Button.onClick.AddListener(() =>
|
||||
{
|
||||
_activeStory = story;
|
||||
_activeStory.ChoosePath(choice.targetPath);
|
||||
Continue();
|
||||
});
|
||||
_choiceInstances.Add(choiceInstance.gameObject);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ public class MenuPanel : MonoBehaviour
|
|||
{
|
||||
tabButton.gameObject.SetActive(!tabButton.RequireDock || GameManager.DockedEntity != null);
|
||||
}
|
||||
_tabs[MenuTab.Local].gameObject.SetActive((GameManager.DockedEntity as OrbitalEntity)?.Story!=null);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
|
|
|
|||
31
GameData/Narrative/Locations/TestA.ink
Normal file
31
GameData/Narrative/Locations/TestA.ink
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#constraint: DistanceFrom start = 0 // Place this location in the starting zone
|
||||
#type: Station // Determines the type of entity for this location (Station/Asteroid/Planet)
|
||||
#security: Open // Security level (Open/Secure/Critical)
|
||||
#faction: Miss Terri // Locations should be tagged with the faction they belong to
|
||||
#name: Test Location 1 // Will set the name of the entity as it appears in game
|
||||
#nameZone: Start Zone // Will name the zone that this location is placed within - locations with named zones are excluded from being placed together
|
||||
#turrets: 1 // Will place defensive turrets around the station
|
||||
|
||||
-> start
|
||||
|
||||
==start==
|
||||
This is the start of the location story.
|
||||
|
||||
+ [Go to location A1] -> A1
|
||||
* This will end the story.
|
||||
|
||||
- They lived happily ever after.
|
||||
-> END
|
||||
|
||||
==A1==
|
||||
This content is in location A1.
|
||||
This is the second line of content in A1.
|
||||
|
||||
+ [Return to start] -> start
|
||||
+ [Go to location A2] -> A2
|
||||
|
||||
==A2==
|
||||
This content is in location A2.
|
||||
|
||||
+ [Return to start] -> start
|
||||
* End the story ->END
|
||||
1
GameData/Narrative/Locations/TestA.json
Normal file
1
GameData/Narrative/Locations/TestA.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"inkVersion":20,"root":[[{"#":"constraint: DistanceFrom start = 0"},{"#":"type: Station"},{"#":"security: Open"},{"#":"faction: Miss Terri"},{"#":"name: Test Location 1"},{"#":"nameZone: Start Zone"},{"->":"start"},["done",{"#f":5,"#n":"g-0"}],null],"done",{"start":[["^This is the start of the location story.","\n","ev","str","^Go to location A1","/str","/ev",{"*":".^.c-0","flg":4},["ev",{"^->":"start.0.8.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^This will end the story.",{"->":"$r","var":true},null]}],{"c-0":["^ ",{"->":"A1"},"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"start.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.8.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["^They lived happily ever after.","\n","end",{"#f":5}]}],{"#f":1}],"A1":[["^This content is in location A1","\n","ev","str","^Return to start","/str","/ev",{"*":".^.c-0","flg":4},["ev",{"^->":"A1.0.8.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":"A1.0.c-1","flg":2},{"s":["^Choice in location A1 ",{"->":"$r","var":true},null]}],{"c-0":["^ ",{"->":"start"},"\n",{"#f":5}],"c-1":["ev",{"^->":"A1.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":"A1.0.8.s"},[{"#n":"$r2"}],"end","\n",{"#f":5}]}],{"#f":1}],"#f":1}],"listDefs":{}}
|
||||
12
GameData/Narrative/Quests/TestQuest.ink
Normal file
12
GameData/Narrative/Quests/TestQuest.ink
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
==A1==
|
||||
#location: TestA // Inject this knot into matching knot in location story
|
||||
#required // This quest is only playable when the target location exists
|
||||
+ [This choice is being injected from TestQuest] -> A1A
|
||||
|
||||
==A1A==
|
||||
This is a thread being injected by TestQuest
|
||||
* [Proceed] -> A1B
|
||||
|
||||
==A1B==
|
||||
This is a child knot in an injected thread
|
||||
* [Exit the injected thread] -> END
|
||||
1
GameData/Narrative/Quests/TestQuest.json
Normal file
1
GameData/Narrative/Quests/TestQuest.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"inkVersion":20,"root":[[["done",{"#f":5,"#n":"g-0"}],null],"done",{"A1":[[{"#":"location: TestA"},{"#":"required"},"ev","str","^This choice is being injected from TestQuest","/str","/ev",{"*":".^.c-0","flg":4},{"c-0":["^ ",{"->":"A1A"},"\n",{"#f":5}]}],{"#f":1}],"A1A":[["^This is a branch thread being injected by TestQuest","\n","ev","str","^Exit the injected thread","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["^ ","end","\n",{"#f":5}]}],{"#f":1}],"#f":1}],"listDefs":{}}
|
||||
BIN
GameData/PlayerSettings.msgpack
(Stored with Git LFS)
BIN
GameData/PlayerSettings.msgpack
(Stored with Git LFS)
Binary file not shown.
|
|
@ -28,4 +28,6 @@ r.db('Aetheria').table('Items').filter(
|
|||
).update({$type:'WeaponItemData'})
|
||||
|
||||
// Set required enum fields in weapons
|
||||
r.db('Aetheria').table('Items').filter({$type:"WeaponItemData"}).update({range:0, caliber:0, weaponType:0, fireTypes:0, modifiers:0})
|
||||
r.db('Aetheria').table('Items').filter({$type:"WeaponItemData"}).update({range:0, caliber:0, weaponType:0, fireTypes:0, modifiers:0})
|
||||
|
||||
r.db('StreamPixels').table('Events').filter({id:"91cb76bb-41b6-4739-883b-5c6ad1fb1c78"}).update({viewers:18})
|
||||
Loading…
Reference in a new issue