private static (ImmutableArray <MapSquare>, ImmutableArray <Tile>) CreateGeometry(Size size, TextureQueue textureQueue)
        {
            var baseTile  = DefaultTile.GrayStone1;
            var nsTexture = baseTile.TextureNorth.Name;
            var ewTexture = baseTile.TextureEast.Name;

            var tiles = new List <Tile> {
                baseTile
            };

            var board =
                new Canvas(size)
                .FillRectangle(size.ToRectangle(), tile: -1)
                .OutlineRectangle(size.ToRectangle(), tile: 0);

            var middleX = HorizontalBuffer + NumGradients;
            var middleY = Height / 2;

            board.Set(middleX, middleY, tile: 1);

            foreach (var darkLevel in Enumerable.Range(1, NumGradients))
            {
                board.Set(middleX - darkLevel, middleY, tile: tiles.Count);

                var newNS = nsTexture + "Dark" + darkLevel;
                var newEW = ewTexture + "Dark" + darkLevel;

                tiles.Add(baseTile with
                {
                    TextureNorth = newNS,
                    TextureSouth = newNS,
                    TextureEast  = newEW,
                    TextureWest  = newEW,
                });

                textureQueue.Add(new CompositeTexture(newNS, 64, 64, ImmutableArray.Create(
                                                          new Patch(nsTexture, 0, 0),
                                                          new Patch(nsTexture, 0, 0, Blend: new ColorBlend("000000", Alpha: 0.1 * darkLevel)))));
                textureQueue.Add(new CompositeTexture(newEW, 64, 64, ImmutableArray.Create(
                                                          new Patch(ewTexture, 0, 0),
                                                          new Patch(ewTexture, 0, 0, Blend: new ColorBlend("000000", Alpha: 0.1 * darkLevel)))));
            }

            foreach (var lightLevel in Enumerable.Range(1, NumGradients))
            {
                board.Set(middleX + lightLevel, middleY, tile: tiles.Count);

                var newNS = nsTexture + "Light" + lightLevel;
                var newEW = ewTexture + "Light" + lightLevel;

                tiles.Add(baseTile with
                {
                    TextureNorth = newNS,
                    TextureSouth = newNS,
                    TextureEast  = newEW,
                    TextureWest  = newEW,
                });

                textureQueue.Add(new CompositeTexture(newNS, 64, 64, ImmutableArray.Create(
                                                          new Patch(nsTexture, 0, 0),
                                                          new Patch(nsTexture, 0, 0, Blend: new ColorBlend("FFFFFF", Alpha: 0.1 * lightLevel)))));
                textureQueue.Add(new CompositeTexture(newEW, 64, 64, ImmutableArray.Create(
                                                          new Patch(ewTexture, 0, 0),
                                                          new Patch(ewTexture, 0, 0, Blend: new ColorBlend("FFFFFF", Alpha: 0.1 * lightLevel)))));
            }

            return(board.ToPlaneMap(), tiles.ToImmutableArray());
        }
示例#2
0
    static (ImmutableArray <MapSquare>, ImmutableArray <Sector>, ImmutableArray <Tile>) CreateGeometry(
        Size size,
        ConnectedArea cave,
        CellBoard alternateFloor,
        CellBoard alternateCeiling,
        LightMap floorLight,
        LightMap ceilingLight,
        TextureQueue textureQueue,
        string texturePrefix)
    {
        var planeMap = new Canvas(size);

        double minLight  = 0.2;
        double darkStep  = (1 - minLight) / ceilingLight.Range.DarkLevels;
        double maxLight  = 1.1;
        double lightStep = (maxLight - 1) / ceilingLight.Range.LightLevels;


        double GetAlpha(int light) =>
        light switch
        {
            0 => 0,
            int pos when pos > 0 => pos * lightStep,
            int neg when neg < 0 => - neg * darkStep,
            _ => throw new InvalidOperationException("Impossible")
        };


        string GetTextureName(Corners corners, int light, bool isEastWest = false)
        {
            string name = $"t{(int)corners:D2}{light:+#;-#;#}{(isEastWest ? "dark" : "")}";

            var patches = ImmutableArray.CreateBuilder <Patch>();

            if (light > 0)
            {
                patches.Add(
                    new Patch(
                        $"{texturePrefix}{(int)corners:D2}",
                        0,
                        0,
                        Blend: new ColorBlend("FFFFFF", GetAlpha(light))));
            }
            else if (light < 0)
            {
                patches.Add(
                    new Patch(
                        $"{texturePrefix}{(int)corners:D2}",
                        0,
                        0,
                        Blend: new ColorBlend("000000", GetAlpha(light))));
            }
            else
            {
                patches.Add(
                    new Patch(
                        $"{texturePrefix}{(int)corners:D2}",
                        0,
                        0));
            }

            if (isEastWest)
            {
                patches.Add(
                    new Patch(
                        $"{texturePrefix}{(int)corners:D2}",
                        0,
                        0,
                        Blend: new ColorBlend("000000"),
                        Style: RenderStyle.Translucent,
                        Alpha: 0.075));
            }

            textureQueue.Add(new CompositeTexture(name, 256, 256, patches.ToImmutable(), XScale: 4, YScale: 4));
            return(name);
        }

        Corners GetCorners(CellBoard board, Position pos) => Corner.CreateFromUpperLeft(
            upperLeft: pos, on: p => board[p] == CellType.Dead);

        Corners GetSideCorners(Position left, Position right) => Corner.Create(
            topLeft: alternateCeiling[left] == CellType.Dead,
            topRight: alternateCeiling[right] == CellType.Dead,
            bottomLeft: alternateFloor[left] == CellType.Dead,
            bottomRight: alternateFloor[right] == CellType.Dead
            );

        int GetSideLight(Position p) => (ceilingLight[p] + floorLight[p]) / 2;

        var sectorSequence = new ModelSequence <SectorDescription, Sector>(description =>
                                                                           new Sector(
                                                                               TextureCeiling: GetTextureName(description.Ceiling, description.CeilingLight),
                                                                               TextureFloor: GetTextureName(description.Floor, description.FloorLight)));
        var tileSequence = new ModelSequence <TileDescription, Tile>(description =>
                                                                     new Tile(
                                                                         TextureEast: GetTextureName(description.EastCorners, description.EastLight, isEastWest: true),
                                                                         TextureNorth: GetTextureName(description.NorthCorners, description.NorthLight),
                                                                         TextureWest: GetTextureName(description.WestCorners, description.WestLight, isEastWest: true),
                                                                         TextureSouth: GetTextureName(description.SouthCorners, description.SouthLight),
                                                                         TextureOverhead: GetTextureName(description.FloorCorners, 0)));

        for (int y = 0; y < size.Height; y++)
        {
            for (int x = 0; x < size.Width; x++)
            {
                var pos = new Position(x, y);

                int tileId = -1;
                if (!cave.Contains(pos))
                {
                    tileId = tileSequence.GetIndex(new TileDescription(
                                                       NorthCorners: GetSideCorners(left: pos + Offset.Right, right: pos),
                                                       EastCorners: GetSideCorners(left: pos + Offset.DownAndRight, right: pos + Offset.Right),
                                                       SouthCorners: GetSideCorners(left: pos + Offset.Down, right: pos + Offset.DownAndRight),
                                                       WestCorners: GetSideCorners(left: pos, right: pos + Offset.Down),
                                                       FloorCorners: GetCorners(alternateFloor, pos),
                                                       NorthLight: GetSideLight(pos + Offset.Up),
                                                       EastLight: GetSideLight(pos + Offset.Right),
                                                       SouthLight: GetSideLight(pos + Offset.Down),
                                                       WestLight: GetSideLight(pos + Offset.Left)));
                }

                int sectorId = sectorSequence.GetIndex(new SectorDescription(
                                                           Floor: GetCorners(alternateFloor, pos),
                                                           Ceiling: GetCorners(alternateCeiling, pos),
                                                           FloorLight: floorLight[pos],
                                                           CeilingLight: ceilingLight[pos]));

                planeMap.Set(x, y,
                             tile: tileId,
                             sector: sectorId,
                             zone: 0);
            }
        }

        return(
            planeMap.ToPlaneMap(),
            sectorSequence.GetDefinitions().ToImmutableArray(),
            tileSequence.GetDefinitions().ToImmutableArray());
    }
        public void CaveMap()
        {
            var textureQueue = new TextureQueue();

            textureQueue.Add(
                new CompositeTexture("CRSFA0",
                                     Width: 35,
                                     Height: 37,
                                     Namespace: TextureNamespace.Sprite,
                                     XScale: 2,
                                     YScale: 2,
                                     Offset: new TextureOffset(17, 32),
                                     Patches: ImmutableArray.Create(new Patch("CRYSTAL", 0, 0))),
                new CompositeTexture("CRSCA0",
                                     Width: 35,
                                     Height: 37,
                                     Namespace: TextureNamespace.Sprite,
                                     XScale: 2,
                                     YScale: 2,
                                     Offset: new TextureOffset(17, 133),
                                     Patches: ImmutableArray.Create(new Patch("CRYSTAL", 0, 0, FlipY: true))));

            var map = WolfCaveMapGenerator.Create(seed: 13, texturePrefix: "TILE", textureQueue: textureQueue);

            Load(new List <ILump> {
                new Marker("P_START")
            }
                 .AddRangeAndContinue(
                     Enumerable.Range(0, 16)
                     .Select(i => new DataLump(
                                 $"TILE{i:d2}",
                                 (byte[])(Resource.ResourceManager.GetObject($"tile{i:00}", CultureInfo.InvariantCulture) ??
                                          throw new ArgumentException("Somehow the name was wrong")))))
                 .AddRangeAndContinue(textureQueue.RenderQueue.Select(r =>
                                                                      DataLump.ReadFromStream(r.Item2.Name, r.Item1.RenderTo)))
                 .AddRangeAndContinue(new ILump[]
            {
                new Marker("P_END"),
                new Marker("S_START"),
                new DataLump("CRYSTAL", Resource.crystal),
                new Marker("S_END"),
                DataLump.ReadFromStream("TEXTURES",
                                        stream => TexturesWriter.Write(textureQueue.Definitions, stream)),
                new DataLump("DECORATE",
                             @"actor CeilingCrystal
{
	states
	{
		Spawn:
			CRSC A -1
			stop
	}
}
actor FloorCrystal
{
	states
	{
		Spawn:
			CRSF A -1
			stop
	}
}"),
                new Marker("MAP01"),
                new UwmfLump("TEXTMAP", map),
                new Marker("ENDMAP")
            }));
        }