Example #1
0
        protected virtual IEnumerator GenerateMainPath()
        {
            ChangeStatus(GenerationStatus.MainPath);
            nextNodeIndex = 0;
            List <GraphNode> handledNodes = new List <GraphNode>(DungeonFlow.Nodes.Count);
            bool             isDone       = false;
            int i = 0;

            // Keep track of these now, we'll need them later when we know the actual length of the dungeon
            List <List <TileSet> >  tileSets   = new List <List <TileSet> >(targetLength);
            List <DungeonArchetype> archetypes = new List <DungeonArchetype>(targetLength);
            List <GraphNode>        nodes      = new List <GraphNode>(targetLength);
            List <GraphLine>        lines      = new List <GraphLine>(targetLength);

            // We can't rigidly stick to the target length since we need at least one room for each node and that might be more than targetLength
            while (!isDone)
            {
                float     depth       = Mathf.Clamp(i / (float)(targetLength - 1), 0, 1);
                GraphLine lineSegment = DungeonFlow.GetLineAtDepth(depth);

                // This should never happen
                if (lineSegment == null)
                {
                    yield return(Wait(InnerGenerate(true)));

                    yield break;
                }

                // We're on a new line segment, change the current archetype
                if (lineSegment != previousLineSegment)
                {
                    currentArchetype    = lineSegment.DungeonArchetypes[RandomStream.Next(0, lineSegment.DungeonArchetypes.Count)];
                    previousLineSegment = lineSegment;
                }

                List <TileSet> useableTileSets = null;
                GraphNode      nextNode        = null;
                var            orderedNodes    = DungeonFlow.Nodes.OrderBy(x => x.Position).ToArray();

                // Determine which node comes next
                foreach (var node in orderedNodes)
                {
                    if (depth >= node.Position && !handledNodes.Contains(node))
                    {
                        nextNode = node;
                        handledNodes.Add(node);
                        break;
                    }
                }

                // Assign the TileSets to use based on whether we're on a node or a line segment
                if (nextNode != null)
                {
                    useableTileSets = nextNode.TileSets;
                    nextNodeIndex   = (nextNodeIndex >= orderedNodes.Length - 1) ? -1 : nextNodeIndex + 1;
                    archetypes.Add(null);
                    lines.Add(null);
                    nodes.Add(nextNode);

                    if (nextNode == orderedNodes[orderedNodes.Length - 1])
                    {
                        isDone = true;
                    }
                }
                else
                {
                    useableTileSets = currentArchetype.TileSets;
                    archetypes.Add(currentArchetype);
                    lines.Add(lineSegment);
                    nodes.Add(null);
                }

                tileSets.Add(useableTileSets);

                i++;
            }

            int tileRetryCount         = 0;
            int totalForLoopRetryCount = 0;

            for (int j = 0; j < tileSets.Count; j++)
            {
                var attachTo = (j == 0) ? null : currentDungeon.MainPathTiles[currentDungeon.MainPathTiles.Count - 1];
                var tile     = AddTile(attachTo, tileSets[j], j / (float)(tileSets.Count - 1), archetypes[j]);

                // if no tile could be generated delete last successful tile and retry from previous index
                // else return false
                if (j > 5 && tile == null && tileRetryCount < 5 && totalForLoopRetryCount < 20)
                {
                    Tile previousTile = currentDungeon.MainPathTiles[j - 1];

                    foreach (var doorway in previousTile.Placement.AllDoorways)
                    {
                        allDoorways.Remove(doorway);
                    }

                    // If the tile we're removing was placed by tile injection, be sure to place the injected tile back on the pending list
                    InjectedTile previousInjectedTile;
                    if (injectedTiles.TryGetValue(previousTile, out previousInjectedTile))
                    {
                        tilesPendingInjection.Add(previousInjectedTile);
                        injectedTiles.Remove(previousTile);
                    }

                    currentDungeon.RemoveLastConnection();
                    currentDungeon.RemoveTile(previousTile);
                    UnityUtil.Destroy(previousTile.gameObject);

                    j -= 2;                     // -2 because loop adds 1
                    tileRetryCount++;
                    totalForLoopRetryCount++;
                }
                else if (tile == null)
                {
                    yield return(Wait(InnerGenerate(true)));

                    yield break;
                }
                else
                {
                    tile.Node      = nodes[j];
                    tile.Line      = lines[j];
                    tileRetryCount = 0;


                    // Wait for a frame to allow for animated loading screens, etc
                    if (ShouldSkipFrame(true))
                    {
                        yield return(GetRoomPause());
                    }
                }
            }

            yield break;             // Required for generation to run synchronously
        }