/// <summary>Scans the map in chunks, evaluating all actors in each.</summary> CPos?FindCoarseAttackLocationToSupportPower(SupportPowerInstance readyPower) { CPos?bestLocation = null; var bestAttractiveness = 0; var powerDecision = powerDecisions[readyPower.Info.OrderName]; if (powerDecision == null) { AIUtils.BotDebug("Bot Bug: FindAttackLocationToSupportPower, couldn't find powerDecision for {0}", readyPower.Info.OrderName); return(null); } var map = world.Map; var checkRadius = powerDecision.CoarseScanRadius; for (var i = 0; i < map.MapSize.X; i += checkRadius) { for (var j = 0; j < map.MapSize.Y; j += checkRadius) { var tl = new MPos(i, j); var br = new MPos(i + checkRadius, j + checkRadius); var region = new CellRegion(map.Grid.Type, tl, br); // HACK: The AI code should not be messing with raw coordinate transformations var wtl = world.Map.CenterOfCell(tl.ToCPos(map)); var wbr = world.Map.CenterOfCell(br.ToCPos(map)); var targets = world.ActorMap.ActorsInBox(wtl, wbr); var frozenTargets = player.FrozenActorLayer != null?player.FrozenActorLayer.FrozenActorsInRegion(region) : Enumerable.Empty <FrozenActor>(); var consideredAttractiveness = powerDecision.GetAttractiveness(targets, player) + powerDecision.GetAttractiveness(frozenTargets, player); if (consideredAttractiveness <= bestAttractiveness || consideredAttractiveness < powerDecision.MinimumAttractiveness) { continue; } bestAttractiveness = consideredAttractiveness; bestLocation = new MPos(i, j).ToCPos(map); } } return(bestLocation); }
static void ReadTiles(Map map, IniFile file, int2 fullSize) { var terrainInfo = (ITemplatedTerrainInfo)Game.ModData.DefaultTerrainInfo[map.Tileset]; var mapSection = file.GetSection("IsoMapPack5"); var data = Convert.FromBase64String(mapSection.Aggregate(string.Empty, (a, b) => a + b.Value)); var cells = (fullSize.X * 2 - 1) * fullSize.Y; var lzoPackSize = cells * 11 + 4; // last 4 bytes contains a lzo pack header saying no more data is left var isoMapPack = new byte[lzoPackSize]; UnpackLZO(data, isoMapPack); var mf = new MemoryStream(isoMapPack); for (var i = 0; i < cells; i++) { var rx = mf.ReadUInt16(); var ry = mf.ReadUInt16(); var tilenum = mf.ReadUInt16(); /*var zero1 = */ mf.ReadInt16(); var subtile = mf.ReadUInt8(); var z = mf.ReadUInt8(); /*var zero2 = */ mf.ReadUInt8(); var dx = rx - ry + fullSize.X - 1; var dy = rx + ry - fullSize.X - 1; var mapCell = new MPos(dx / 2, dy); var cell = mapCell.ToCPos(map); if (map.Tiles.Contains(cell)) { if (!terrainInfo.Templates.ContainsKey(tilenum)) { tilenum = subtile = 0; } map.Tiles[cell] = new TerrainTile(tilenum, subtile); map.Height[cell] = z; } } }
void UpdateTint(MPos uv) { var offset = rowStride * uv.V + 6 * uv.U; if (ignoreTint[offset]) { var noTint = float3.Ones; for (var i = 0; i < 6; i++) { var v = vertices[offset + i]; vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, noTint); } return; } // Allow the terrain tint to vary linearly across the cell to smooth out the staircase effect // This is done by sampling the lighting the corners of the sprite, even though those pixels are // transparent for isometric tiles var tl = worldRenderer.TerrainLighting; var pos = map.CenterOfCell(uv.ToCPos(map)); var step = map.Grid.Type == MapGridType.RectangularIsometric ? 724 : 512; var weights = new[] { tl.TintAt(pos + new WVec(-step, -step, 0)), tl.TintAt(pos + new WVec(step, -step, 0)), tl.TintAt(pos + new WVec(step, step, 0)), tl.TintAt(pos + new WVec(-step, step, 0)) }; // Apply tint directly to the underlying vertices // This saves us from having to re-query the sprite information, which has not changed for (var i = 0; i < 6; i++) { var v = vertices[offset + i]; vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, weights[CornerVertexMap[i]]); } dirtyRows.Add(uv.V); }
CellRegion CalculateVisibleCells(bool insideBounds) { var map = worldRenderer.World.Map; // Calculate the viewport corners in "projected wpos" (at ground level), and // this to an equivalent projected cell for the two corners var tl = map.CellContaining(worldRenderer.ProjectedPosition(TopLeft)).ToMPos(map); var br = map.CellContaining(worldRenderer.ProjectedPosition(BottomRight)).ToMPos(map); // Diamond tile shapes don't have straight edges, and so we need // an additional cell margin to include the cells that are half // visible on each edge. if (map.TileShape == TileShape.Diamond) { tl = new MPos(tl.U - 1, tl.V - 1); br = new MPos(br.U + 1, br.V + 1); } // Clamp to the visible map bounds, if requested if (insideBounds) { tl = map.Clamp(tl); br = map.Clamp(br); } // Cells can be pushed up from below if they have non-zero height. // Each height step is equivalent to 512 WDist units, which is // one MPos step for diamond cells, but only half a MPos step // for classic cells. Doh! var heightOffset = map.TileShape == TileShape.Diamond ? map.MaximumTerrainHeight : map.MaximumTerrainHeight / 2; br = new MPos(br.U, br.V + heightOffset); // Finally, make sure that this region doesn't extend outside the map area. tl = map.MapHeight.Value.Clamp(tl); br = map.MapHeight.Value.Clamp(br); return(new CellRegion(map.TileShape, tl.ToCPos(map), br.ToCPos(map))); }
public void WorldLoaded(World w, WorldRenderer wr) { /* based on SmudgeLayer.cs */ var first = sideSprites.First().Value.First(); var sheet = first.Sheet; if (sideSprites.Values.Any(sprites => sprites.Any(s => s.Sheet != sheet))) throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); var blendMode = first.BlendMode; if (sideSprites.Values.Any(sprites => sprites.Any(s => s.BlendMode != blendMode))) throw new InvalidDataException("Smudges specify different blend modes. " + "Try using different smudge types for smudges that use different blend modes."); render = new TerrainSpriteLayer(w, wr, sheet, blendMode, wr.Palette(Info.Palette), wr.World.Type != WorldType.Editor); var tilesLayer = w.Map.Tiles; for (var v = 0; v < tilesLayer.Size.Height; v++) { for (var u = 0; u < tilesLayer.Size.Width; u++) { var mpos = new MPos(u, v); var tile = tilesLayer[mpos]; if (tile.Type == 143) { ClearSides clear = ClearSides.None; if (u > 0) { var leftPos = new MPos(u - 1, v); var leftTile = tilesLayer[leftPos]; if (!(leftTile.Type >= 126 && leftTile.Type <= 143) && !(leftTile.Type >= 160 && leftTile.Type <= 175)) { clear |= ClearSides.Left; } } if (v > 0) { var topPos = new MPos(u, v - 1); var topTile = tilesLayer[topPos]; if (!(topTile.Type >= 126 && topTile.Type <= 143) && !(topTile.Type >= 160 && topTile.Type <= 175)) { clear |= ClearSides.Top; } } if (u < tilesLayer.Size.Width - 1) { var rightPos = new MPos(u + 1, v); var rightTile = tilesLayer[rightPos]; if (!(rightTile.Type >= 126 && rightTile.Type <= 143) && !(rightTile.Type >= 160 && rightTile.Type <= 175)) { clear |= ClearSides.Right; } } if (v < tilesLayer.Size.Height - 1) { var bottomPos = new MPos(u, v + 1); var bottomTile = tilesLayer[bottomPos]; if (!(bottomTile.Type >= 126 && bottomTile.Type <= 143) && !(bottomTile.Type >= 160 && bottomTile.Type <= 175)) { clear |= ClearSides.Bottom; } } if (clear != ClearSides.None) { CPos cpos = mpos.ToCPos(w.Map); Sprite sprite = sideSprites["rock"][SpriteMap[clear]]; render.Update(cpos, sprite); } } if (tile.Type == 175) { ClearSides clear = ClearSides.None; if (u > 0) { var leftPos = new MPos(u - 1, v); var leftTile = tilesLayer[leftPos]; if (!(leftTile.Type >= 160 && leftTile.Type <= 175)) { clear |= ClearSides.Left; } } if (v > 0) { var topPos = new MPos(u, v - 1); var topTile = tilesLayer[topPos]; if (!(topTile.Type >= 160 && topTile.Type <= 175)) { clear |= ClearSides.Top; } } if (u < tilesLayer.Size.Width - 1) { var rightPos = new MPos(u + 1, v); var rightTile = tilesLayer[rightPos]; if (!(rightTile.Type >= 160 && rightTile.Type <= 175)) { clear |= ClearSides.Right; } } if (v < tilesLayer.Size.Height - 1) { var bottomPos = new MPos(u, v + 1); var bottomTile = tilesLayer[bottomPos]; if (!(bottomTile.Type >= 160 && bottomTile.Type <= 175)) { clear |= ClearSides.Bottom; } } if (clear != ClearSides.None) { CPos cpos = mpos.ToCPos(w.Map); Sprite sprite = sideSprites["rough"][SpriteMap[clear]]; render.Update(cpos, sprite); } } if (tile.Type == 159) { ClearSides clear = ClearSides.None; if (u > 0) { var leftPos = new MPos(u - 1, v); var leftTile = tilesLayer[leftPos]; if (!(leftTile.Type >= 144 && leftTile.Type <= 159)) { clear |= ClearSides.Left; } } if (v > 0) { var topPos = new MPos(u, v - 1); var topTile = tilesLayer[topPos]; if (!(topTile.Type >= 144 && topTile.Type <= 159)) { clear |= ClearSides.Top; } } if (u < tilesLayer.Size.Width - 1) { var rightPos = new MPos(u + 1, v); var rightTile = tilesLayer[rightPos]; if (!(rightTile.Type >= 144 && rightTile.Type <= 159)) { clear |= ClearSides.Right; } } if (v < tilesLayer.Size.Height - 1) { var bottomPos = new MPos(u, v + 1); var bottomTile = tilesLayer[bottomPos]; if (!(bottomTile.Type >= 144 && bottomTile.Type <= 159)) { clear |= ClearSides.Bottom; } } if (clear != ClearSides.None) { CPos cpos = mpos.ToCPos(w.Map); Sprite sprite = sideSprites["dune"][SpriteMap[clear]]; render.Update(cpos, sprite); } } } } }
static void ReadOverlay(Map map, IniFile file, int2 fullSize) { var overlaySection = file.GetSection("OverlayPack"); var overlayCompressed = Convert.FromBase64String(overlaySection.Aggregate(string.Empty, (a, b) => a + b.Value)); var overlayPack = new byte[1 << 18]; var temp = new byte[1 << 18]; UnpackLCW(overlayCompressed, overlayPack, temp); var overlayDataSection = file.GetSection("OverlayDataPack"); var overlayDataCompressed = Convert.FromBase64String(overlayDataSection.Aggregate(string.Empty, (a, b) => a + b.Value)); var overlayDataPack = new byte[1 << 18]; UnpackLCW(overlayDataCompressed, overlayDataPack, temp); for (var y = 0; y < fullSize.Y; y++) { for (var x = fullSize.X * 2 - 2; x >= 0; x--) { var dx = (ushort)x; var dy = (ushort)(y * 2 + x % 2); var uv = new MPos(dx / 2, dy); var rx = (ushort)((dx + dy) / 2 + 1); var ry = (ushort)(dy - rx + fullSize.X + 1); if (!map.Resources.Contains(uv)) { continue; } var idx = rx + 512 * ry; var overlayType = overlayPack[idx]; if (overlayType == 0xFF) { continue; } string actorType; if (OverlayToActor.TryGetValue(overlayType, out actorType)) { var ar = new ActorReference(actorType) { new LocationInit(uv.ToCPos(map)), new OwnerInit("Neutral") }; map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save())); continue; } var resourceType = ResourceFromOverlay .Where(kv => kv.Value.Contains(overlayType)) .Select(kv => kv.Key) .FirstOrDefault(); if (resourceType != 0) { map.Resources[uv] = new ResourceTile(resourceType, overlayDataPack[idx]); continue; } Console.WriteLine("{0} unknown overlay {1}", uv, overlayType); } } }
public void WorldLoaded(World w, WorldRenderer wr) { /* based on SmudgeLayer.cs */ var first = sideSprites.First().Value.First(); var sheet = first.Sheet; if (sideSprites.Values.Any(sprites => sprites.Any(s => s.Sheet != sheet))) { throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); } var blendMode = first.BlendMode; if (sideSprites.Values.Any(sprites => sprites.Any(s => s.BlendMode != blendMode))) { throw new InvalidDataException("Smudges specify different blend modes. " + "Try using different smudge types for smudges that use different blend modes."); } render = new TerrainSpriteLayer(w, wr, sheet, blendMode, wr.Palette(Info.Palette), wr.World.Type != WorldType.Editor); var tilesLayer = w.Map.Tiles; for (var v = 0; v < tilesLayer.Size.Height; v++) { for (var u = 0; u < tilesLayer.Size.Width; u++) { var pos = new MPos(u, v); var tile = tilesLayer[pos]; if (tile.Type == D2MapUtils.RockTile) { var index = D2MapUtils.SmoothIndexForPos(tilesLayer, pos); if (index != 15) { CPos cpos = pos.ToCPos(w.Map); Sprite sprite = sideSprites["rock"][index]; render.Update(cpos, sprite); } } if (tile.Type == D2MapUtils.DuneTile) { var index = D2MapUtils.SmoothIndexForPos(tilesLayer, pos); if (index != 15) { CPos cpos = pos.ToCPos(w.Map); Sprite sprite = sideSprites["dune"][index]; render.Update(cpos, sprite); } } if (tile.Type == D2MapUtils.RoughTile) { var index = D2MapUtils.SmoothIndexForPos(tilesLayer, pos); if (index != 15) { CPos cpos = pos.ToCPos(w.Map); Sprite sprite = sideSprites["rough"][index]; render.Update(cpos, sprite); } } } } }
CellRegion CalculateVisibleCells(bool insideBounds) { var map = worldRenderer.World.Map; // Calculate the viewport corners in "projected wpos" (at ground level), and // this to an equivalent projected cell for the two corners var tl = map.CellContaining(worldRenderer.ProjectedPosition(TopLeft)).ToMPos(map); var br = map.CellContaining(worldRenderer.ProjectedPosition(BottomRight)).ToMPos(map); // Diamond tile shapes don't have straight edges, and so we need // an additional cell margin to include the cells that are half // visible on each edge. if (map.TileShape == TileShape.Diamond) { tl = new MPos(tl.U - 1, tl.V - 1); br = new MPos(br.U + 1, br.V + 1); } // Clamp to the visible map bounds, if requested if (insideBounds) { tl = map.Clamp(tl); br = map.Clamp(br); } // Cells can be pushed up from below if they have non-zero height. // Each height step is equivalent to 512 WDist units, which is // one MPos step for diamond cells, but only half a MPos step // for classic cells. Doh! var heightOffset = map.TileShape == TileShape.Diamond ? map.MaximumTerrainHeight : map.MaximumTerrainHeight / 2; br = new MPos(br.U, br.V + heightOffset); // Finally, make sure that this region doesn't extend outside the map area. tl = map.MapHeight.Value.Clamp(tl); br = map.MapHeight.Value.Clamp(br); return new CellRegion(map.TileShape, tl.ToCPos(map), br.ToCPos(map)); }
static void ReadTiles(Map map, IniFile file, int2 fullSize) { var tileset = Game.ModData.DefaultTileSets[map.Tileset]; var mapSection = file.GetSection("IsoMapPack5"); var data = Convert.FromBase64String(mapSection.Aggregate(string.Empty, (a, b) => a + b.Value)); int cells = (fullSize.X * 2 - 1) * fullSize.Y; int lzoPackSize = cells * 11 + 4; // last 4 bytes contains a lzo pack header saying no more data is left var isoMapPack = new byte[lzoPackSize]; UnpackLZO(data, isoMapPack); var mf = new MemoryStream(isoMapPack); for (var i = 0; i < cells; i++) { var rx = mf.ReadUInt16(); var ry = mf.ReadUInt16(); var tilenum = mf.ReadUInt16(); /*var zero1 = */mf.ReadInt16(); var subtile = mf.ReadUInt8(); var z = mf.ReadUInt8(); /*var zero2 = */mf.ReadUInt8(); int dx = rx - ry + fullSize.X - 1; int dy = rx + ry - fullSize.X - 1; var mapCell = new MPos(dx / 2, dy); var cell = mapCell.ToCPos(map); if (map.Tiles.Contains(cell)) { if (!tileset.Templates.ContainsKey(tilenum)) tilenum = subtile = 0; map.Tiles[cell] = new TerrainTile(tilenum, subtile); map.Height[cell] = z; } } }
public void SetBounds(MPos tl, MPos br) { // The tl and br coordinates are inclusive, but the Rectangle // is exclusive. Pad the right and bottom edges to match. Bounds = Rectangle.FromLTRB(tl.U, tl.V, br.U + 1, br.V + 1); CellsInsideBounds = new CellRegion(TileShape, tl.ToCPos(this), br.ToCPos(this)); // Directly calculate the projected map corners in world units avoiding unnecessary // conversions. This abuses the definition that the width of the cell is always // 1024 units, and that the height of two rows is 2048 for classic cells and 1024 // for diamond cells. var wtop = tl.V * 1024; var wbottom = (br.V + 1) * 1024; if (TileShape == TileShape.Diamond) { wtop /= 2; wbottom /= 2; } ProjectedTopLeft = new WPos(tl.U * 1024, wtop, 0); ProjectedBottomRight = new WPos(br.U * 1024 - 1, wbottom - 1, 0); }
void PreSpawnClouds(World world) { var facing = 256 * info.WindDirection / 32; var delta = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing)); /* * The following codes find the middle point in map. Because clouds must * start from an edge to another edge, the paths of clouds * which contain this point will always be the longest path no matter the direction, * as long as the map is a symmetrical shape. * * For example, the middle point in map is "@", @ is (u = X/2, v = Y/2) * You can imagine any wind direction with all edges clouds possibly spawn. * * ____X____ * | | * | | * | @ Y * | | * |_______| * * By using this longest path, we can figure out the number of clouds should * spawn when a certain cloud completely goes over a longest path, which should be * neither too little nor too big compared with the clouds per map-cell later * spawned by `SpawnCloud`. */ var middlePoint = new MPos(world.Map.MapSize.X / 2, world.Map.MapSize.Y / 2); var middlePointTarget = world.Map.CenterOfCell(middlePoint.ToCPos(world.Map)); // lDistance and averageSpeed used are for loop condition below. var longestCloudDistance = System.Math.Abs( (world.Map.DistanceToEdge(middlePointTarget, -delta) + info.Cordon).Length + (world.Map.DistanceToEdge(middlePointTarget, delta) + info.Cordon).Length); var averageCloudSpeed = System.Math.Abs((int)info.Speed.Average(s => s.Length)); var stepPerSpawn = averageCloudSpeed * info.SpawnInterval; var stepPerSpawnVector = stepPerSpawn * delta / 1024; /* * Spawn clouds. * * Try to make clouds spawning cover the entire map, meanwhile * with some randomization. Choose random spawning point and * find startEdge, then add offset to let they go further to cover * the map. The offset will be increased to simulate the movement * the cloud would have made otherwise. */ var offset = WVec.Zero; while (longestCloudDistance > 0) { var position = world.Map.ChooseRandomCell(world.SharedRandom); var target = world.Map.CenterOfCell(position) + new WVec(0, 0, info.CruiseAltitude.Length); var startEdge = target - (world.Map.DistanceToEdge(target, -delta) + info.Cordon).Length * delta / 1024; startEdge += offset; var finishEdge = target + (world.Map.DistanceToEdge(target, delta) + info.Cordon).Length * delta / 1024; var animation = new Animation(world, info.Image, () => WAngle.FromFacing(facing)); animation.PlayRepeating(info.Sequences.Random(world.SharedRandom)); world.AddFrameEndTask(w => w.Add(new Cloud(world, animation, startEdge, finishEdge, facing, info))); offset += stepPerSpawnVector; longestCloudDistance -= stepPerSpawn; } }
public void Resize(int width, int height) { var oldMapTiles = Tiles; var oldMapResources = Resources; var oldMapHeight = Height; var newSize = new Size(width, height); Tiles = CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[MPos.Zero]); Resources = CellLayer.Resize(oldMapResources, newSize, oldMapResources[MPos.Zero]); Height = CellLayer.Resize(oldMapHeight, newSize, oldMapHeight[MPos.Zero]); MapSize = new int2(newSize); var tl = new MPos(0, 0); var br = new MPos(MapSize.X - 1, MapSize.Y - 1); AllCells = new CellRegion(Grid.Type, tl.ToCPos(this), br.ToCPos(this)); SetBounds(new PPos(tl.U + 1, tl.V + 1), new PPos(br.U - 1, br.V - 1)); }
static void ReadOverlay(Map map, IniFile file, int2 fullSize) { var overlaySection = file.GetSection("OverlayPack"); var overlayCompressed = Convert.FromBase64String(overlaySection.Aggregate(string.Empty, (a, b) => a + b.Value)); var overlayPack = new byte[1 << 18]; var temp = new byte[1 << 18]; UnpackLCW(overlayCompressed, overlayPack, temp); var overlayDataSection = file.GetSection("OverlayDataPack"); var overlayDataCompressed = Convert.FromBase64String(overlayDataSection.Aggregate(string.Empty, (a, b) => a + b.Value)); var overlayDataPack = new byte[1 << 18]; UnpackLCW(overlayDataCompressed, overlayDataPack, temp); for (var y = 0; y < fullSize.Y; y++) { for (var x = fullSize.X * 2 - 2; x >= 0; x--) { var dx = (ushort)x; var dy = (ushort)(y * 2 + x % 2); var uv = new MPos(dx / 2, dy); var rx = (ushort)((dx + dy) / 2 + 1); var ry = (ushort)(dy - rx + fullSize.X + 1); if (!map.Resources.Contains(uv)) continue; var idx = rx + 512 * ry; var overlayType = overlayPack[idx]; if (overlayType == 0xFF) continue; string actorType; if (OverlayToActor.TryGetValue(overlayType, out actorType)) { var ar = new ActorReference(actorType) { new LocationInit(uv.ToCPos(map)), new OwnerInit("Neutral") }; map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save())); continue; } var resourceType = ResourceFromOverlay .Where(kv => kv.Value.Contains(overlayType)) .Select(kv => kv.Key) .FirstOrDefault(); if (resourceType != 0) { map.Resources[uv] = new ResourceTile(resourceType, overlayDataPack[idx]); continue; } Console.WriteLine("{0} unknown overlay {1}", uv, overlayType); } } }
Edges GetEdges(MPos uv, Func<MPos, bool> isVisible) { if (!isVisible(uv)) return notVisibleEdges; var cell = uv.ToCPos(map); // If a side is shrouded then we also count the corners. var edge = Edges.None; if (!isVisible((cell + new CVec(0, -1)).ToMPos(map))) edge |= Edges.Top; if (!isVisible((cell + new CVec(1, 0)).ToMPos(map))) edge |= Edges.Right; if (!isVisible((cell + new CVec(0, 1)).ToMPos(map))) edge |= Edges.Bottom; if (!isVisible((cell + new CVec(-1, 0)).ToMPos(map))) edge |= Edges.Left; var ucorner = edge & Edges.AllCorners; if (!isVisible((cell + new CVec(-1, -1)).ToMPos(map))) edge |= Edges.TopLeft; if (!isVisible((cell + new CVec(1, -1)).ToMPos(map))) edge |= Edges.TopRight; if (!isVisible((cell + new CVec(1, 1)).ToMPos(map))) edge |= Edges.BottomRight; if (!isVisible((cell + new CVec(-1, 1)).ToMPos(map))) edge |= Edges.BottomLeft; // RA provides a set of frames for tiles with shrouded // corners but unshrouded edges. We want to detect this // situation without breaking the edge -> corner enabling // in other combinations. The XOR turns off the corner // bits that are enabled twice, which gives the behavior // we want here. return info.UseExtendedIndex ? edge ^ ucorner : edge & Edges.AllCorners; }
public void WorldLoaded(World w, WorldRenderer wr) { /* based on SmudgeLayer.cs */ var first = sideSprites.First().Value.First(); var sheet = first.Sheet; if (sideSprites.Values.Any(sprites => sprites.Any(s => s.Sheet != sheet))) { throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); } var blendMode = first.BlendMode; if (sideSprites.Values.Any(sprites => sprites.Any(s => s.BlendMode != blendMode))) { throw new InvalidDataException("Smudges specify different blend modes. " + "Try using different smudge types for smudges that use different blend modes."); } render = new TerrainSpriteLayer(w, wr, sheet, blendMode, wr.Palette(Info.Palette), wr.World.Type != WorldType.Editor); var tilesLayer = w.Map.Tiles; for (var v = 0; v < tilesLayer.Size.Height; v++) { for (var u = 0; u < tilesLayer.Size.Width; u++) { var mpos = new MPos(u, v); var tile = tilesLayer[mpos]; if (tile.Type == 143) { ClearSides clear = ClearSides.None; if (u > 0) { var leftPos = new MPos(u - 1, v); var leftTile = tilesLayer[leftPos]; if (!(leftTile.Type >= 126 && leftTile.Type <= 143) && !(leftTile.Type >= 160 && leftTile.Type <= 175)) { clear |= ClearSides.Left; } } if (v > 0) { var topPos = new MPos(u, v - 1); var topTile = tilesLayer[topPos]; if (!(topTile.Type >= 126 && topTile.Type <= 143) && !(topTile.Type >= 160 && topTile.Type <= 175)) { clear |= ClearSides.Top; } } if (u < tilesLayer.Size.Width - 1) { var rightPos = new MPos(u + 1, v); var rightTile = tilesLayer[rightPos]; if (!(rightTile.Type >= 126 && rightTile.Type <= 143) && !(rightTile.Type >= 160 && rightTile.Type <= 175)) { clear |= ClearSides.Right; } } if (v < tilesLayer.Size.Height - 1) { var bottomPos = new MPos(u, v + 1); var bottomTile = tilesLayer[bottomPos]; if (!(bottomTile.Type >= 126 && bottomTile.Type <= 143) && !(bottomTile.Type >= 160 && bottomTile.Type <= 175)) { clear |= ClearSides.Bottom; } } if (clear != ClearSides.None) { CPos cpos = mpos.ToCPos(w.Map); Sprite sprite = sideSprites["rock"][SpriteMap[clear]]; render.Update(cpos, sprite); } } if (tile.Type == 175) { ClearSides clear = ClearSides.None; if (u > 0) { var leftPos = new MPos(u - 1, v); var leftTile = tilesLayer[leftPos]; if (!(leftTile.Type >= 160 && leftTile.Type <= 175)) { clear |= ClearSides.Left; } } if (v > 0) { var topPos = new MPos(u, v - 1); var topTile = tilesLayer[topPos]; if (!(topTile.Type >= 160 && topTile.Type <= 175)) { clear |= ClearSides.Top; } } if (u < tilesLayer.Size.Width - 1) { var rightPos = new MPos(u + 1, v); var rightTile = tilesLayer[rightPos]; if (!(rightTile.Type >= 160 && rightTile.Type <= 175)) { clear |= ClearSides.Right; } } if (v < tilesLayer.Size.Height - 1) { var bottomPos = new MPos(u, v + 1); var bottomTile = tilesLayer[bottomPos]; if (!(bottomTile.Type >= 160 && bottomTile.Type <= 175)) { clear |= ClearSides.Bottom; } } if (clear != ClearSides.None) { CPos cpos = mpos.ToCPos(w.Map); Sprite sprite = sideSprites["rough"][SpriteMap[clear]]; render.Update(cpos, sprite); } } if (tile.Type == 159) { ClearSides clear = ClearSides.None; if (u > 0) { var leftPos = new MPos(u - 1, v); var leftTile = tilesLayer[leftPos]; if (!(leftTile.Type >= 144 && leftTile.Type <= 159)) { clear |= ClearSides.Left; } } if (v > 0) { var topPos = new MPos(u, v - 1); var topTile = tilesLayer[topPos]; if (!(topTile.Type >= 144 && topTile.Type <= 159)) { clear |= ClearSides.Top; } } if (u < tilesLayer.Size.Width - 1) { var rightPos = new MPos(u + 1, v); var rightTile = tilesLayer[rightPos]; if (!(rightTile.Type >= 144 && rightTile.Type <= 159)) { clear |= ClearSides.Right; } } if (v < tilesLayer.Size.Height - 1) { var bottomPos = new MPos(u, v + 1); var bottomTile = tilesLayer[bottomPos]; if (!(bottomTile.Type >= 144 && bottomTile.Type <= 159)) { clear |= ClearSides.Bottom; } } if (clear != ClearSides.None) { CPos cpos = mpos.ToCPos(w.Map); Sprite sprite = sideSprites["dune"][SpriteMap[clear]]; render.Update(cpos, sprite); } } } } }
public void WorldLoaded(World w, WorldRenderer wr) { /* based on SmudgeLayer.cs */ var first = sideSprites.First().Value.First(); var sheet2D = first.Sheet2D; //this check can be removed //if (sideSprites.Values.Any(sprites => sprites.Any(s => s.Sheet2D != sheet2D))) // throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); var blendMode = first.BlendMode; if (sideSprites.Values.Any(sprites => sprites.Any(s => s.BlendMode != blendMode))) { throw new InvalidDataException("Smudges specify different blend modes. " + "Try using different smudge types for smudges that use different blend modes."); } // using base TerrainRenderer to avoid using one more renderer through TerrainSpriteLayer class as it was done. //var terrainRenderer = w.WorldActor.TraitOrDefault<IRenderTerrain>(); //to get TerrainRenderer.cs class //TerrainRenderer = terrainRenderer.GetTerrainSpriteLayerRenderer(); //get all Sprites that it has from tileset\*.yaml file //render = TerrainRenderer[Info.Palette]; // Nowadays way to accomplish task is to add one more renderer through TerrainSpriteLayer class and we get one more Batch for total terrain vertexes render = new TerrainSpriteLayer(w, wr, sheet2D, blendMode, wr.Palette(Info.Palette), wr.World.Type != WorldType.Editor, "D2TerrainLayer"); MersenneTwister random = new MersenneTwister(); var tilesLayer = w.Map.Tiles; for (var v = 0; v < tilesLayer.Size.Height; v++) { for (var u = 0; u < tilesLayer.Size.Width; u++) { var pos = new MPos(u, v); var tile = tilesLayer[pos]; if (tile.Type == D2MapUtils.RockTile) { var index = D2MapUtils.SmoothIndexForPos(tilesLayer, pos); if (index != 15) { CPos cpos = pos.ToCPos(w.Map); //ushort sdf; //int ffd = (128 + Convert.ToInt32(index)); //sdf = Convert.ToUInt16(ffd); //var t = new TerrainTile(sdf, 0); //Sprite sprite = wr.Theater.TileSprite(t, 0); Sprite sprite = sideSprites["rock"][index]; render.Update(cpos, sprite); } } if (tile.Type == D2MapUtils.DuneTile) { var index = D2MapUtils.SmoothIndexForPos(tilesLayer, pos); if (index != 15) { CPos cpos = pos.ToCPos(w.Map); //ushort sdf; //int ffd = (144 + Convert.ToInt32(index)); //158 //sdf = Convert.ToUInt16(ffd); //var t = new TerrainTile(sdf, 0); //Sprite sprite = wr.Theater.TileSprite(t, 0); Sprite sprite = sideSprites["dune"][index]; render.Update(cpos, sprite); } } if (tile.Type == D2MapUtils.RoughTile) { var index = D2MapUtils.SmoothIndexForPos(tilesLayer, pos); if (index != 15) { CPos cpos = pos.ToCPos(w.Map); //ushort sdf; //int ffd = (160 + Convert.ToInt32(index)); //sdf = Convert.ToUInt16(ffd); //var t = new TerrainTile(sdf, 0); //Sprite sprite = wr.Theater.TileSprite(t, 0); Sprite sprite = sideSprites["rough"][index]; render.Update(cpos, sprite); } } } } }