using System; using System.Collections.Generic; using System.Linq; using DunGen.Tags; using UnityEngine; using UnityEngine.Serialization; namespace DunGen.Graph { [Serializable] [CreateAssetMenu(fileName = "New Dungeon", menuName = "DunGen/Dungeon Flow", order = 700)] public class DungeonFlow : ScriptableObject, ISerializationCallbackReceiver { [Serializable] public sealed class GlobalPropSettings { public int ID; public IntRange Count; public GlobalPropSettings() { ID = 0; Count = new IntRange(0, 1); } public GlobalPropSettings(int id, IntRange count) { ID = id; Count = count; } } public enum TagConnectionMode { Accept = 0, Reject = 1 } public enum BranchPruneMode { AnyTagPresent = 0, AllTagsMissing = 1 } public const int FileVersion = 1; [SerializeField] [FormerlySerializedAs("GlobalPropGroupIDs")] private List globalPropGroupID_obsolete = new List(); [SerializeField] [FormerlySerializedAs("GlobalPropRanges")] private List globalPropRanges_obsolete = new List(); public IntRange Length = new IntRange(5, 10); public BranchMode BranchMode; public IntRange BranchCount = new IntRange(1, 5); public List GlobalProps = new List(); public KeyManager KeyManager; [Range(0f, 1f)] public float DoorwayConnectionChance; public bool RestrictConnectionToSameSection; public List TileInjectionRules = new List(); public TagConnectionMode TileTagConnectionMode; public List TileConnectionTags = new List(); public BranchPruneMode BranchTagPruneMode = BranchPruneMode.AllTagsMissing; public List BranchPruneTags = new List(); public List Nodes = new List(); public List Lines = new List(); [SerializeField] private int currentFileVersion; public void Reset() { TileSet[] tileSets = new TileSet[0]; DungeonArchetype[] archetypes = new DungeonArchetype[0]; new DungeonFlowBuilder(this).AddNode(tileSets, "Start").AddLine(archetypes).AddNode(tileSets, "Goal") .Complete(); } public GraphLine GetLineAtDepth(float normalizedDepth) { normalizedDepth = Mathf.Clamp(normalizedDepth, 0f, 1f); if (normalizedDepth == 0f) { return Lines[0]; } if (normalizedDepth == 1f) { return Lines[Lines.Count - 1]; } foreach (GraphLine line in Lines) { if (normalizedDepth >= line.Position && normalizedDepth < line.Position + line.Length) { return line; } } Debug.LogError("GetLineAtDepth was unable to find a line at depth " + normalizedDepth + ". This shouldn't happen."); return null; } public DungeonArchetype[] GetUsedArchetypes() { return Lines.SelectMany((GraphLine x) => x.DungeonArchetypes).ToArray(); } public TileSet[] GetUsedTileSets() { List list = new List(); foreach (GraphNode node in Nodes) { list.AddRange(node.TileSets); } foreach (GraphLine line in Lines) { foreach (DungeonArchetype dungeonArchetype in line.DungeonArchetypes) { list.AddRange(dungeonArchetype.TileSets); list.AddRange(dungeonArchetype.BranchCapTileSets); } } return list.ToArray(); } public bool ShouldPruneTileWithTags(TagContainer tileTags) { return BranchTagPruneMode switch { BranchPruneMode.AnyTagPresent => tileTags.HasAnyTag(BranchPruneTags.ToArray()), BranchPruneMode.AllTagsMissing => !tileTags.HasAnyTag(BranchPruneTags.ToArray()), _ => throw new NotImplementedException($"BranchPruneMode {BranchTagPruneMode} is not implemented"), }; } public void OnBeforeSerialize() { currentFileVersion = 1; } public void OnAfterDeserialize() { if (currentFileVersion < 1) { for (int i = 0; i < globalPropGroupID_obsolete.Count; i++) { int id = globalPropGroupID_obsolete[i]; IntRange count = globalPropRanges_obsolete[i]; GlobalProps.Add(new GlobalPropSettings(id, count)); } globalPropGroupID_obsolete.Clear(); globalPropRanges_obsolete.Clear(); } } public bool CanTilesConnect(Tile tileA, Tile tileB) { if (tileA == null || tileB == null) { return false; } if (TileConnectionTags.Count == 0) { return true; } return TileTagConnectionMode switch { TagConnectionMode.Accept => HasMatchingTagPair(tileA, tileB), TagConnectionMode.Reject => !HasMatchingTagPair(tileA, tileB), _ => throw new NotImplementedException($"{typeof(TagConnectionMode).Name}.{TileTagConnectionMode} is not implemented"), }; } public bool CanDoorwaysConnect(Tile tileA, Tile tileB, Doorway doorwayA, Doorway doorwayB) { foreach (TileConnectionRule item in DoorwayPairFinder.CustomConnectionRules.OrderByDescending((TileConnectionRule r) => r.Priority)) { TileConnectionRule.ConnectionResult connectionResult = item.Delegate(tileA, tileB, doorwayA, doorwayB); if (connectionResult != TileConnectionRule.ConnectionResult.Passthrough) { return connectionResult == TileConnectionRule.ConnectionResult.Allow; } } if (DoorwaySocket.CanSocketsConnect(doorwayA.Socket, doorwayB.Socket)) { return CanTilesConnect(tileA, tileB); } return false; } private bool HasMatchingTagPair(Tile tileA, Tile tileB) { foreach (TagPair tileConnectionTag in TileConnectionTags) { if ((tileA.Tags.HasTag(tileConnectionTag.TagA) && tileB.Tags.HasTag(tileConnectionTag.TagB)) || (tileB.Tags.HasTag(tileConnectionTag.TagA) && tileA.Tags.HasTag(tileConnectionTag.TagB))) { return true; } } return false; } } }