protected virtual void GatherTilesToInject() { Random injectionRandomStream = new Random(ChosenSeed); // Gather from DungeonFlow foreach (var rule in DungeonFlow.TileInjectionRules) { // Ignore invalid rules if (rule.TileSet == null || (!rule.CanAppearOnMainPath && !rule.CanAppearOnBranchPath)) { continue; } bool isOnMainPath = (!rule.CanAppearOnBranchPath) ? true : (!rule.CanAppearOnMainPath) ? false : injectionRandomStream.NextDouble() > 0.5; InjectedTile injectedTile = new InjectedTile(rule.TileSet, isOnMainPath, rule.NormalizedPathDepth.GetRandom(injectionRandomStream), rule.NormalizedBranchDepth.GetRandom(injectionRandomStream), rule.IsRequired); tilesPendingInjection.Add(injectedTile); } // Gather from external delegates if (TileInjectionMethods != null) { TileInjectionMethods(injectionRandomStream, ref tilesPendingInjection); } }
protected virtual Tile AddTile(Tile attachTo, IEnumerable <TileSet> useableTileSets, float normalizedDepth, DungeonArchetype archetype, TilePlacementResult result = TilePlacementResult.None) { bool isOnMainPath = (Status == GenerationStatus.MainPath); bool isFirstTile = attachTo == null; // Check list of tiles to inject InjectedTile chosenInjectedTile = null; int injectedTileIndexToRemove = -1; bool isPlacingSpecificRoom = isOnMainPath && (archetype == null); if (tilesPendingInjection != null && !isPlacingSpecificRoom) { float pathDepth = (isOnMainPath) ? normalizedDepth : attachTo.Placement.PathDepth / (float)(targetLength - 1); float branchDepth = (isOnMainPath) ? 0 : normalizedDepth; for (int i = 0; i < tilesPendingInjection.Count; i++) { var injectedTile = tilesPendingInjection[i]; if (injectedTile.ShouldInjectTileAtPoint(isOnMainPath, pathDepth, branchDepth)) { chosenInjectedTile = injectedTile; injectedTileIndexToRemove = i; break; } } } // Select appropriate tile weights IEnumerable <GameObjectChance> chanceEntries; if (chosenInjectedTile != null) { chanceEntries = new List <GameObjectChance>(chosenInjectedTile.TileSet.TileWeights.Weights); } else { chanceEntries = useableTileSets.SelectMany(x => x.TileWeights.Weights); } // Apply constraint overrides bool allowRepeatTile = (isFirstTile) ? true : attachTo.AllowImmediateRepeats; if (OverrideAllowImmediateRepeats) { allowRepeatTile = AllowImmediateRepeats; } bool allowRotation = (isFirstTile) ? false : attachTo.AllowRotation; if (OverrideAllowTileRotation) { allowRotation = AllowTileRotation; } DoorwayPairFinder doorwayPairFinder = new DoorwayPairFinder() { RandomStream = RandomStream, Archetype = archetype, GetTileTemplateDelegate = GetTileTemplate, IsOnMainPath = isOnMainPath, NormalizedDepth = normalizedDepth, PreviousTile = attachTo, PreviousPrefab = (attachTo == null) ? null : placedTilePrefabs[attachTo], UpVector = UpVector, AllowRotation = allowRotation, TileWeights = new List <GameObjectChance>(chanceEntries), IsTileAllowedPredicate = (Tile previousTile, GameObject previousPrefab, GameObject prefab, ref float weight) => { bool isRepeat = (prefab == previousPrefab); return(!isRepeat || allowRepeatTile); }, }; int?maxPairingAttempts = (UseMaximumPairingAttempts) ? (int?)MaxPairingAttempts : null; Queue <DoorwayPair> pairsToTest = doorwayPairFinder.GetDoorwayPairs(maxPairingAttempts); TilePlacementResult lastTileResult = TilePlacementResult.NoValidTile; Tile createdTile = null; while (pairsToTest.Count > 0) { var pair = pairsToTest.Dequeue(); lastTileResult = TryPlaceTile(pair, archetype, out createdTile); if (lastTileResult == TilePlacementResult.None) { break; } else { AddTilePlacementResult(lastTileResult); } } // Successfully placed the tile if (lastTileResult == TilePlacementResult.None) { // We've successfully injected the tile, so we can remove it from the pending list now if (chosenInjectedTile != null) { injectedTiles[createdTile] = chosenInjectedTile; tilesPendingInjection.RemoveAt(injectedTileIndexToRemove); if (isOnMainPath) { targetLength++; } } return(createdTile); } else { return(null); } }