diff --git a/DunGenPlus/DunGenPlus/API.cs b/DunGenPlus/DunGenPlus/API.cs index 89aa1de..cb2967b 100644 --- a/DunGenPlus/DunGenPlus/API.cs +++ b/DunGenPlus/DunGenPlus/API.cs @@ -9,6 +9,7 @@ using DunGen.Graph; using DunGenPlus.Generation; using LethalLevelLoader; using UnityEngine; +using static DunGenPlus.Components.DoorwayCleanupScripting.DCSConnectorBlockerSpawnedPrefab; namespace DunGenPlus { @@ -128,6 +129,8 @@ namespace DunGenPlus /// /// DO NOT USE! + /// + /// Registers the connection between to that's specifically created during . /// /// public static void AddTileToMainPathDictionary(Dictionary dictionary){ diff --git a/DunGenPlus/DunGenPlus/Collections/DunGenExtenderPropertiesCollection.cs b/DunGenPlus/DunGenPlus/Collections/DunGenExtenderPropertiesCollection.cs index 6d4f127..2d8d79b 100644 --- a/DunGenPlus/DunGenPlus/Collections/DunGenExtenderPropertiesCollection.cs +++ b/DunGenPlus/DunGenPlus/Collections/DunGenExtenderPropertiesCollection.cs @@ -17,8 +17,7 @@ namespace DunGenPlus.Collections { internal const string MainRoomTilePrefabTooltip = "The Tile prefab where the additional main paths will start from.\n\nCannot be null if MainPathCount is more than 1."; internal const string CopyNodeBehaviourTooltip = "Defines how the nodes list is copied onto the additional main paths.\n\nCopyFromMainPathPosition: nodes will copy based on the MainRoomTilePrefab's position in the main path.\nCopyFromNodeList: nodes will copy based on the MainRoomTilePrefab's position in the node list + 1."; internal const string MainPathDetailsTooltip = "Overrides certain DungeonFlow values during the main path generation.\n\nThe order of items in this list correspond to the order of the main paths being generated.\nThe first item in this list will activate for the first main path, the second item for the second main path, and so on. If there are more main paths than items in this list, the last item is used instead."; - internal const string LocalMainPathGlobalPropsTooltip = "Limits the amount of Global Props that can spawn on a single main path.\n\nThis does not afffect the global limit defined in DungeonFlow."; - + [Tooltip(MainPathCountTooltip)] [Range(1, 9)] @@ -29,8 +28,6 @@ namespace DunGenPlus.Collections { public CopyNodeBehaviour CopyNodeBehaviour = CopyNodeBehaviour.CopyFromMainPathPosition; [Tooltip(MainPathDetailsTooltip)] public List MainPathDetails = new List(); - [Tooltip(LocalMainPathGlobalPropsTooltip)] - public List LocalMainPathGlobalProps = new List(); public MainPathExtender GetMainPathDetails(int index) { var count = MainPathDetails.Count; @@ -44,7 +41,6 @@ namespace DunGenPlus.Collections { MainRoomTilePrefab = props.MainRoomTilePrefab; CopyNodeBehaviour = props.CopyNodeBehaviour; MainPathDetails = props.MainPathDetails; - LocalMainPathGlobalProps = props.LocalMainPathGlobalProps; } internal MainPathProperties Copy() { diff --git a/DunGenPlus/DunGenPlus/Collections/LocalGlobalPropSettings.cs b/DunGenPlus/DunGenPlus/Collections/LocalGlobalPropSettings.cs new file mode 100644 index 0000000..874083f --- /dev/null +++ b/DunGenPlus/DunGenPlus/Collections/LocalGlobalPropSettings.cs @@ -0,0 +1,26 @@ +using DunGen; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace DunGenPlus.Collections { + [System.Serializable] + public class LocalGlobalPropSettings { + + internal const string GlobalPropLimitTooltip = "If true, when PostProcess reaches the local limit of Global Props for all main paths but does not reach the global limit, use the remaining props in this main path to reach the global limit."; + + public int ID; + public IntRange Count; + [Tooltip(GlobalPropLimitTooltip)] + public bool UseToReachGlobalPropLimit; + + public LocalGlobalPropSettings(int id, IntRange count, bool useToReachGlobalPropLimit) { + ID = id; + Count = count; + UseToReachGlobalPropLimit = useToReachGlobalPropLimit; + } + } +} diff --git a/DunGenPlus/DunGenPlus/DunGenPlus.csproj b/DunGenPlus/DunGenPlus/DunGenPlus.csproj index 21f252c..74817aa 100644 --- a/DunGenPlus/DunGenPlus/DunGenPlus.csproj +++ b/DunGenPlus/DunGenPlus/DunGenPlus.csproj @@ -134,6 +134,7 @@ + diff --git a/DunGenPlus/DunGenPlus/DunGenPlus/DunGenPlus.dll b/DunGenPlus/DunGenPlus/DunGenPlus/DunGenPlus.dll index 18fac0c..ea4ec61 100644 Binary files a/DunGenPlus/DunGenPlus/DunGenPlus/DunGenPlus.dll and b/DunGenPlus/DunGenPlus/DunGenPlus/DunGenPlus.dll differ diff --git a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs index 404d9aa..e62f5ba 100644 --- a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs +++ b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs @@ -126,6 +126,8 @@ namespace DunGenPlus.Generation { } public static void AddTileToMainPathDictionary(Dictionary dictionary){ + if (!DunGenPlusGenerator.Active) return; + foreach(var pair in dictionary){ tileMainPath.Add(pair.Value, GetMainPathIndexFromTileProxy(pair.Key)); } diff --git a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorMiscellaneous.cs b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorMiscellaneous.cs index f19fe34..cb929d8 100644 --- a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorMiscellaneous.cs +++ b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorMiscellaneous.cs @@ -98,7 +98,7 @@ namespace DunGenPlus.Generation { // Copied and pasted from DunGen public static void ProcessGlobalPropsPerMainPath(DungeonGenerator dungeonGenerator){ - var localIDs = Properties.MainPathProperties.LocalMainPathGlobalProps.Select(x => x.ID).ToHashSet(); + var localIDs = Properties.MainPathProperties.MainPathDetails.SelectMany(d => d.LocalGroupProps).Select(x => x.ID).ToHashSet(); // first parameter int is the GlobalProp ID // second parameter is the List of GameObjectChanceTable indexed by the main path index @@ -166,6 +166,19 @@ namespace DunGenPlus.Generation { return i; } + int ProcessRemainingGlobalPropID(GameObjectChanceTable[] tables, int count){ + count = Mathf.Clamp(count, 0, tables.Sum(t => t.Weights.Count)); + var i = 0; + while(i < count){ + var random = GameObjectChanceTable.GetCombinedRandom(dungeonGenerator.RandomStream, true, 0f, tables); + if (random != null) { + random.SetActive(true); + } + ++i; + } + return i; + } + using(var enumerator = globalDictionary.GetEnumerator()){ while(enumerator.MoveNext()){ var pair = enumerator.Current; @@ -178,12 +191,12 @@ namespace DunGenPlus.Generation { .Where(x => x.ID == pair.Key) .FirstOrDefault(); - if (globalPropSettings != null){ + if (globalPropSettings != null){ var tableClone = pair.Value.Clone(); var globalMax = globalPropSettings.Count.GetRandom(dungeonGenerator.RandomStream); var spawned = ProcessGlobalPropID(tableClone, globalMax, 0, globalMax); - //Plugin.logger.LogError($"Spawned {spawned} ({spawned}/{globalMax})"); + Plugin.logger.LogDebug($"Global ID: {pair.Key} ({spawned} / {globalMax})"); list.Add(pair.Key); } } @@ -193,29 +206,65 @@ namespace DunGenPlus.Generation { using(var enumerator = localDictionary.GetEnumerator()){ while(enumerator.MoveNext()){ var pair = enumerator.Current; - if (list.Contains(pair.Key)){ + var globalPropId = pair.Key; + if (list.Contains(globalPropId)){ Plugin.logger.LogWarning("Dungeon Flow contains multiple entries for the global prop group ID: " + pair.Key.ToString() + ". Only the first entry will be used."); } else { //Plugin.logger.LogWarning($"{pair.Key}: Local"); var globalPropSettings = dungeonGenerator.DungeonFlow.GlobalProps - .Where(x => x.ID == pair.Key) + .Where(x => x.ID == globalPropId) .FirstOrDefault(); - var localPropSettings = Properties.MainPathProperties.LocalMainPathGlobalProps - .Where(x => x.ID == pair.Key) - .FirstOrDefault(); - - if (globalPropSettings != null && localPropSettings != null){ + + if (globalPropSettings != null){ var globalCount = 0; - foreach(var path in pair.Value.Values){ - var tableClone = path.Clone(); - var globalMax = globalPropSettings.Count.GetRandom(dungeonGenerator.RandomStream); + var globalMax = globalPropSettings.Count.GetRandom(dungeonGenerator.RandomStream); + var pathDictionary = pair.Value; + Plugin.logger.LogDebug($"Local ID: {pair.Key} (Max {globalMax})"); + + var toRemoveKeys = new List(); + + foreach(var pathPair in pathDictionary){ + // try and get local main path properites based on key of Dictionary + var mainPathIndex = pathPair.Key; + var localGroupProps = Properties.MainPathProperties.GetMainPathDetails(mainPathIndex).LocalGroupProps; + var localPropSettings = localGroupProps + .Where(x => x.ID == globalPropId) + .FirstOrDefault(); + + if (localPropSettings == null) { + Plugin.logger.LogDebug($"Main Path {mainPathIndex}: No local ID defined, skipping"); + continue; + } + + var tableClone = pathPair.Value.Clone(); var localMax = localPropSettings.Count.GetRandom(dungeonGenerator.RandomStream); - var spawned = ProcessGlobalPropID(tableClone, localMax, globalCount, globalMax); + var spawned = ProcessGlobalPropID(tableClone, localMax, globalCount, globalMax); globalCount += spawned; + Plugin.logger.LogDebug($"Main Path {mainPathIndex}: Local ({spawned} / {localMax}), Global ({globalCount} / {globalMax})"); + + // all dictionaries that we done using get throw out + if (!localPropSettings.UseToReachGlobalPropLimit) toRemoveKeys.Add(mainPathIndex); + //Plugin.logger.LogError($"Spawned {spawned} ({globalCount}/{globalMax})"); } + + foreach(var key in toRemoveKeys){ + pathDictionary.Remove(key); + } + + // spawn the last remaining global props if possible + if (globalCount < globalMax && pathDictionary.Count > 0) { + var combine = string.Join(", ", pathDictionary.Keys); + Plugin.logger.LogDebug($"Combining main paths ({combine}) into one GameObjectChanceTable"); + + var combinedTable = pathDictionary.Select(d => d.Value).ToArray(); + var spawned = ProcessRemainingGlobalPropID(combinedTable, globalMax - globalCount); + globalCount += spawned; + Plugin.logger.LogDebug($"Spawned remaining props ({globalCount} / {globalMax})"); + } + list.Add(pair.Key); } } diff --git a/DunGenPlus/DunGenPlus/MainPathExtender.cs b/DunGenPlus/DunGenPlus/MainPathExtender.cs index 6cde072..77680cd 100644 --- a/DunGenPlus/DunGenPlus/MainPathExtender.cs +++ b/DunGenPlus/DunGenPlus/MainPathExtender.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine; +using DunGenPlus.Collections; namespace DunGenPlus { @@ -24,6 +25,8 @@ namespace DunGenPlus { [CreateAssetMenu(fileName = "Main Path Extender", menuName = "DunGenExtender/Main Path Extender", order = 2)] public class MainPathExtender : ScriptableObject { + internal const string LocalMainPathGlobalPropsTooltip = "Limits the amount of Global Props that can spawn on a single main path.\n\nThis does not afffect the global limit defined in DungeonFlow."; + public PropertyOverride Length = new PropertyOverride(false, new IntRange(5, 10)); public PropertyOverride BranchMode = new PropertyOverride(false, DunGen.BranchMode.Local); @@ -32,6 +35,9 @@ namespace DunGenPlus { public PropertyOverride> Nodes = new PropertyOverride>(false, new List()); public PropertyOverride> Lines = new PropertyOverride>(false, new List()); + [Tooltip(LocalMainPathGlobalPropsTooltip)] + public List LocalGroupProps = new List(); + [Header("DEV ONLY: DON'T TOUCH")] [Attributes.ReadOnly] public string Version = "0"; diff --git a/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs b/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs index 694e6d4..9c6bcf1 100644 --- a/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs +++ b/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs @@ -373,14 +373,10 @@ namespace DunGenPlus.Patches { [HarmonyPrefix] [HarmonyPatch(typeof(DungeonGenerator), "ProcessGlobalProps")] public static bool ProcessGlobalPropsPatch(ref DungeonGenerator __instance){ - if (DunGenPlusGenerator.Active){ - var list = DunGenPlusGenerator.Properties.MainPathProperties.LocalMainPathGlobalProps; - if (list != null && list.Count > 0) { - Plugin.logger.LogDebug("Performing Local Global Props algorithm"); - DunGenPlusGenerator.ProcessGlobalPropsPerMainPath(__instance); - return false; - } - + if (DunGenPlusGenerator.Active && DunGenPlusGenerator.Properties.MainPathProperties.MainPathDetails.Any(d => d.LocalGroupProps.Count > 0)){ + Plugin.logger.LogDebug("Performing Local Global Props algorithm"); + DunGenPlusGenerator.ProcessGlobalPropsPerMainPath(__instance); + return false; } return true; } diff --git a/DunGenPlus/DunGenPlus/Plugin.cs b/DunGenPlus/DunGenPlus/Plugin.cs index f35cfa2..741183e 100644 --- a/DunGenPlus/DunGenPlus/Plugin.cs +++ b/DunGenPlus/DunGenPlus/Plugin.cs @@ -25,7 +25,7 @@ namespace DunGenPlus { internal const string modGUID = "dev.ladyalice.dungenplus"; private const string modName = "Dungeon Generation Plus"; - private const string modVersion = "1.2.1"; + private const string modVersion = "1.3.0"; internal readonly Harmony Harmony = new Harmony(modGUID);