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()); }
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") })); }