public void Deserialize(BinaryReader reader) { Width = reader.ReadInt32(); Height = reader.ReadInt32(); Stories = reader.ReadInt32(); var size = Width * Height; Walls = new WallTile[Stories][]; for (int l=0;l<Stories;l++) { Walls[l] = new WallTile[size]; for (int i = 0; i < size; i++) Walls[l][i] = WallTileSerializer.Deserialize(reader); } Floors = new FloorTile[Stories][]; for (int l = 0; l < Stories; l++) { Floors[l] = new FloorTile[size]; for (int i = 0; i < size; i++) Floors[l][i] = new FloorTile { Pattern = reader.ReadUInt16() }; } WallsDirty = reader.ReadBoolean(); FloorsDirty = reader.ReadBoolean(); }
//for first floor gen, curRoom should be 1. For floors above, it should be the last genmap result /// <summary> /// Generates the room map for the specified walls array. /// </summary> public void GenerateMap(WallTile[] Walls, FloorTile[] Floors, int width, int height, List<VMRoom> rooms) { Map = new uint[width*height]; //although 0 is the base of the array, room 1 is known to simantics as room 0. //values of 0 indicate the room has not been chosen in that location yet. bool noFloorBad = (rooms.Count > 1); this.Width = width; this.Height = height; //flood fill recursively. Each time choose find and choose the first "0" as the base. //The first recursion (outside) cannot fill into diagonals. bool remaining = true; bool outside = true; while (remaining) { var spread = new Stack<Point>(); remaining = false; for (int i = 0; i < Map.Length; i++) { if (Map[i] == 0) { ExpectedTile = Floors[i].Pattern; //if (ExpectedTile == 0 && noFloorBad) continue; if (ExpectedTile < 65534) ExpectedTile = 0; remaining = true; Map[i] = (ushort)rooms.Count; spread.Push(new Point(i % width, i / width)); break; } } if (remaining) { int rminX = spread.Peek().X; int rmaxX = rminX; int rminY = spread.Peek().Y; int rmaxY = rminY; var wallObs = new List<VMObstacle>(); ushort area = 0; while (spread.Count > 0) { area++; var item = spread.Pop(); if (item.X > rmaxX) rmaxX = item.X; if (item.X < rminX) rminX = item.X; if (item.Y > rmaxY) rmaxY = item.Y; if (item.Y < rminY) rminY = item.Y; var plusX = (item.X+1)%width; var minX = (item.X + width - 1) % width; var plusY = (item.Y+1)%height; var minY = (item.Y + height - 1) % height; var mainWalls = Walls[item.X + item.Y * width]; int obsX = item.X << 4; int obsY = item.Y << 4; if ((mainWalls.Segments & WallSegments.HorizontalDiag) > 0) { wallObs.Add(new VMObstacle(obsX + 9, obsY - 1, obsX + 17, obsY + 7)); wallObs.Add(new VMObstacle(obsX + 4, obsY + 4, obsX + 12, obsY + 12)); wallObs.Add(new VMObstacle(obsX - 1, obsY + 9, obsX + 7, obsY + 17)); } if ((mainWalls.Segments & WallSegments.VerticalDiag) > 0) { wallObs.Add(new VMObstacle(obsX - 1, obsY - 1, obsX + 7, obsY + 7)); wallObs.Add(new VMObstacle(obsX + 4, obsY + 4, obsX + 12, obsY + 12)); wallObs.Add(new VMObstacle(obsX + 9, obsY + 9, obsX + 17, obsY + 17)); } if ((byte)mainWalls.Segments > 15) continue; //don't spread on diagonals for now var PXWalls = Walls[plusX + item.Y * width]; var PYWalls = Walls[item.X + plusY * width]; if ((mainWalls.Segments & WallSegments.TopLeft) > 0 && !mainWalls.TopLeftDoor) wallObs.Add(new VMObstacle(obsX - 3, obsY - 3, obsX + 6, obsY + 19)); if ((mainWalls.Segments & WallSegments.TopRight) > 0 && !mainWalls.TopRightDoor) wallObs.Add(new VMObstacle(obsX - 3, obsY - 3, obsX + 19, obsY + 6)); if ((mainWalls.Segments & WallSegments.BottomLeft) > 0 && !PYWalls.TopRightDoor) wallObs.Add(new VMObstacle(obsX - 3, obsY + 13, obsX + 19, obsY + 19)); if ((mainWalls.Segments & WallSegments.BottomRight) > 0 && !PXWalls.TopLeftDoor) wallObs.Add(new VMObstacle(obsX + 13, obsY - 3, obsX + 19, obsY + 19)); // if (((PXWalls.Segments & WallSegments.TopLeft) == 0 || PXWalls.TopLeftStyle != 1)) SpreadOnto(Walls, Floors, plusX, item.Y, 0, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad); if (((mainWalls.Segments & WallSegments.TopLeft) == 0 || mainWalls.TopLeftStyle != 1)) SpreadOnto(Walls, Floors, minX, item.Y, 2, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad); if (((PYWalls.Segments & WallSegments.TopRight) == 0 || PYWalls.TopRightStyle != 1)) SpreadOnto(Walls, Floors, item.X, plusY, 1, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad); if (((mainWalls.Segments & WallSegments.TopRight) == 0 || mainWalls.TopRightStyle != 1)) SpreadOnto(Walls, Floors, item.X, minY, 3, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad); } var bounds = new Rectangle(rminX, rminY, (rmaxX - rminX) + 1, (rmaxY - rminY) + 1); var roomObs = GenerateRoomObs((ushort)rooms.Count, bounds); OptimizeObstacles(wallObs); OptimizeObstacles(roomObs); rooms.Add(new VMRoom { IsOutside = outside || ExpectedTile > 65533, IsPool = ExpectedTile > 65533, Bounds = bounds, WallObs = wallObs, RoomObs = roomObs, Area = area }); outside = false; } } }
private static void SpreadOnto(WallTile[] walls, FloorTile[] floors, int x, int y, int inDir, uint[] map, int width, int height, Stack<Point> spread, ushort room, ushort expectedTile, bool noAir) { var wall = walls[x + y * width]; var floor = floors[x + y * width].Pattern; if ((expectedTile > 0 && expectedTile != floor) || (expectedTile == 0 && floor > 65533)) { return; } if ((wall.Segments & WallSegments.HorizontalDiag) > 0) { if (inDir < 2) { //bottom (bottom right pattern) if ((map[x + y * width] & (uint)0x0000FFFF)>0) return; //don't spread onto map[x + y * width] |= room; } else { //top (bottom left pattern) if ((map[x + y * width] & (uint)0xFFFF0000) > 0) return; //don't spread onto map[x + y * width] |= (uint)room<<16; } //if (!floorMode) walls[x + y * width] = wall; } else if ((wall.Segments & WallSegments.VerticalDiag) > 0) { if (inDir > 0 && inDir < 3) { //left if ((map[x + y * width] & (uint)0x0000FFFF) > 0) return; //don't spread onto map[x + y * width] |= room; } else { //right if ((map[x + y * width] & (uint)0xFFFF0000) > 0) return; //don't spread onto map[x + y * width] |= (uint)room << 16; } //if (!floorMode) walls[x + y * width] = wall; } else { if (map[x + y * width] > 0) return; map[x + y * width] = (uint)(room | (room<<16)); } spread.Push(new Point(x, y)); }
private void GenerateWallData(WallTile[] walls, List<int> wallsAt, bool notTop) { var width = blueprint.Width; var height = blueprint.Height; Cuts = new WallCuts[width * height]; DownJunctions = new JunctionFlags[width * height]; UpJunctions = new JunctionFlags[width * height]; foreach (var off in wallsAt) { var wall = walls[off]; var x = off % width; var y = off / width; var result = new WallCuts(); if (notTop && WallsDownAt(x, y)) { var cuts = GetCutEdges(off % width, off / width); if (wall.TopLeftThick && wall.TopLeftStyle != 255) { if (cuts != 0) { if ((cuts & CutawayEdges.NegativeX) == CutawayEdges.NegativeX) result.TLCut = WallCut.Up; //if we are on the very edge of the cut we're up else if ((cuts & CutawayEdges.PositiveY) == CutawayEdges.PositiveY) { if ((cuts & CutawayEdges.NegativeY) == CutawayEdges.NegativeY) { result.TLCut = WallCut.Down; //special case, cuts at both sides... just put wall down } else { result.TLCut = WallCut.DownRightUpLeft; } } else if ((cuts & CutawayEdges.NegativeY) == CutawayEdges.NegativeY) { result.TLCut = WallCut.DownLeftUpRight; } else result.TLCut = WallCut.Down; } else { result.TLCut = WallCut.Down; } } if (wall.TopRightStyle == 1) //NOTE: top right style also includes diagonals! { if (wall.Segments == WallSegments.HorizontalDiag) { if (cuts != 0) { var cutOnLeft = (cuts & (CutawayEdges.PositiveY | CutawayEdges.NegativeX)) > 0; var cutOnRight = (cuts & (CutawayEdges.NegativeY | CutawayEdges.PositiveX)) > 0; if (cutOnLeft && cutOnRight) result.TRCut = WallCut.Down; else if (cutOnLeft) result.TRCut = WallCut.DownRightUpLeft; else if (cutOnRight) result.TRCut = WallCut.DownLeftUpRight; else result.TRCut = WallCut.Down; } else { result.TRCut = WallCut.Down; } } else if (wall.Segments == WallSegments.VerticalDiag) { if (cuts != 0) //this info is not useful for front rotation, but is useful for sides. { var cutOnLeft = (cuts & (CutawayEdges.PositiveY | CutawayEdges.PositiveX)) > 0; var cutOnRight = (cuts & (CutawayEdges.NegativeY | CutawayEdges.NegativeX)) > 0; if (cutOnLeft && cutOnRight) result.TRCut = WallCut.Down; else if (cutOnLeft) result.TRCut = WallCut.DownRightUpLeft; else if (cutOnRight) result.TRCut = WallCut.DownLeftUpRight; else result.TRCut = WallCut.Down; } else { result.TRCut = WallCut.Down; } } else { if (cuts != 0) { if ((cuts & CutawayEdges.NegativeY) == CutawayEdges.NegativeY) result.TRCut = WallCut.Up; //if we are on the very edge of the cut we're up else if ((cuts & CutawayEdges.PositiveX) == CutawayEdges.PositiveX) { if ((cuts & CutawayEdges.NegativeX) == CutawayEdges.NegativeX) { //special case, cuts at both sides... just put wall down result.TRCut = WallCut.Down; } else { result.TRCut = WallCut.DownLeftUpRight; } } else if ((cuts & CutawayEdges.NegativeX) == CutawayEdges.NegativeX) { result.TRCut = WallCut.DownRightUpLeft; } else result.TRCut = WallCut.Down; } else { result.TRCut = WallCut.Down; } } } } //add to relevant junctions if ((wall.Segments & WallSegments.TopLeft) > 0 && !(wall.TopLeftDoor && result.TLCut > 0) && wall.TopLeftThick) { if (result.TLCut > 0) { DownJunctions[off] |= JunctionFlags.BottomLeft; if (y < height) DownJunctions[off + width] |= JunctionFlags.TopRight; } else { UpJunctions[off] |= JunctionFlags.BottomLeft; if (y < height) UpJunctions[off + width] |= JunctionFlags.TopRight; } } if ((wall.Segments & WallSegments.TopRight) > 0 && !(wall.TopRightDoor && result.TRCut > 0) && wall.TopRightThick) { if (result.TRCut > 0) { DownJunctions[off] |= JunctionFlags.BottomRight; if (x < width) DownJunctions[off + 1] |= JunctionFlags.TopLeft; } else { UpJunctions[off] |= JunctionFlags.BottomRight; if (x < width) UpJunctions[off + 1] |= JunctionFlags.TopLeft; } } if (wall.Segments == WallSegments.VerticalDiag && (wall.TopRightStyle == 1 || wall.TopRightStyle == 255)) { if (result.TRCut > 0) { DownJunctions[off] |= JunctionFlags.DiagBottom; if (x < width && y < height) DownJunctions[off + 1 + width] |= JunctionFlags.DiagTop; } else { UpJunctions[off] |= JunctionFlags.DiagBottom; if (x < width && y < height) UpJunctions[off + 1 + width] |= JunctionFlags.DiagTop; } } else if (wall.Segments == WallSegments.HorizontalDiag && (wall.TopRightStyle == 1 || wall.TopRightStyle == 255)) { if (result.TRCut > 0) { if (x < width) DownJunctions[off + 1] |= JunctionFlags.DiagLeft; if (y < height) DownJunctions[off + width] |= JunctionFlags.DiagRight; } else { if (x < width) UpJunctions[off + 1] |= JunctionFlags.DiagLeft; if (y < height) UpJunctions[off + width] |= JunctionFlags.DiagRight; } } Cuts[off] = result; } }
private WallTile RotateWall(WorldRotation rot, WallTile input, short x, short y, sbyte level) { int rotN = (int)rot; var output = new WallTile(); if (rot != 0) { if (input.Segments == WallSegments.HorizontalDiag) { output.Segments = ((rotN % 2) == 0) ? WallSegments.HorizontalDiag : WallSegments.VerticalDiag; output.TopRightStyle = input.TopRightStyle; switch (rotN) { case 1: output.BottomRightPattern = input.BottomLeftPattern; output.BottomLeftPattern = input.BottomRightPattern; output.TopLeftStyle = input.TopLeftPattern; output.TopLeftPattern = input.TopLeftStyle; break; case 2: output.BottomRightPattern = input.BottomLeftPattern; //flip sides output.BottomLeftPattern = input.BottomRightPattern; output.TopLeftStyle = input.TopLeftPattern; output.TopLeftPattern = input.TopLeftStyle; break; case 3: output.BottomRightPattern = input.BottomRightPattern; output.BottomLeftPattern = input.BottomLeftPattern; output.TopLeftStyle = input.TopLeftStyle; output.TopLeftPattern = input.TopLeftPattern; break; } } else if (input.Segments == WallSegments.VerticalDiag) { output.Segments = ((rotN % 2) == 0) ? WallSegments.VerticalDiag : WallSegments.HorizontalDiag; output.TopRightStyle = input.TopRightStyle; switch (rotN) { case 1: output.BottomRightPattern = input.BottomRightPattern; output.BottomLeftPattern = input.BottomLeftPattern; output.TopLeftStyle = input.TopLeftStyle; output.TopLeftPattern = input.TopLeftPattern; break; case 2: output.BottomRightPattern = input.BottomLeftPattern; //flip sides output.BottomLeftPattern = input.BottomRightPattern; output.TopLeftStyle = input.TopLeftPattern; output.TopLeftPattern = input.TopLeftStyle; break; case 3: output.BottomRightPattern = input.BottomLeftPattern; output.BottomLeftPattern = input.BottomRightPattern; output.TopLeftStyle = input.TopLeftPattern; output.TopLeftPattern = input.TopLeftStyle; break; } } else { switch (rotN) { case 1: if ((input.Segments & WallSegments.TopLeft) > 0) output.Segments |= WallSegments.TopRight; if ((input.Segments & WallSegments.TopRight) > 0) output.Segments |= WallSegments.BottomRight; if ((input.Segments & WallSegments.BottomRight) > 0) output.Segments |= WallSegments.BottomLeft; if ((input.Segments & WallSegments.BottomLeft) > 0) output.Segments |= WallSegments.TopLeft; output.TopLeftPattern = input.BottomLeftPattern; output.TopRightPattern = input.TopLeftPattern; output.BottomRightPattern = input.TopRightPattern; output.BottomLeftPattern = input.BottomRightPattern; if (y + 1 < blueprint.Height) { var newLeft = blueprint.GetWall(x, (short)(y + 1), level); output.TopLeftStyle = newLeft.TopRightStyle; output.ObjSetTLStyle = newLeft.ObjSetTRStyle; output.TopLeftDoor = newLeft.TopRightDoor; } output.TopRightStyle = input.TopLeftStyle; output.ObjSetTRStyle = input.ObjSetTLStyle; output.TopRightDoor = input.TopLeftDoor; break; case 2: if ((input.Segments & WallSegments.TopLeft) > 0) output.Segments |= WallSegments.BottomRight; if ((input.Segments & WallSegments.TopRight) > 0) output.Segments |= WallSegments.BottomLeft; if ((input.Segments & WallSegments.BottomRight) > 0) output.Segments |= WallSegments.TopLeft; if ((input.Segments & WallSegments.BottomLeft) > 0) output.Segments |= WallSegments.TopRight; output.TopLeftPattern = input.BottomRightPattern; output.TopRightPattern = input.BottomLeftPattern; output.BottomRightPattern = input.TopLeftPattern; output.BottomLeftPattern = input.TopRightPattern; if (y + 1 < blueprint.Height) { var newRight = blueprint.GetWall(x, (short)(y + 1), level); output.TopRightStyle = newRight.TopRightStyle; output.ObjSetTRStyle = newRight.ObjSetTRStyle; output.TopRightDoor = newRight.TopRightDoor; } if (x + 1 < blueprint.Width) { var newLeft = blueprint.GetWall((short)(x + 1), y, level); output.TopLeftStyle = newLeft.TopLeftStyle; output.ObjSetTLStyle = newLeft.ObjSetTLStyle; output.TopLeftDoor = newLeft.TopLeftDoor; } break; case 3: if ((input.Segments & WallSegments.TopLeft) > 0) output.Segments |= WallSegments.BottomLeft; if ((input.Segments & WallSegments.TopRight) > 0) output.Segments |= WallSegments.TopLeft; if ((input.Segments & WallSegments.BottomRight) > 0) output.Segments |= WallSegments.TopRight; if ((input.Segments & WallSegments.BottomLeft) > 0) output.Segments |= WallSegments.BottomRight; output.TopLeftPattern = input.TopRightPattern; output.TopRightPattern = input.BottomRightPattern; output.BottomRightPattern = input.BottomLeftPattern; output.BottomLeftPattern = input.TopLeftPattern; output.TopLeftStyle = input.TopRightStyle; output.TopLeftDoor = input.TopRightDoor; output.ObjSetTLStyle = input.ObjSetTRStyle; if (x + 1 < blueprint.Width) { var newRight = blueprint.GetWall((short)(x + 1), y, level); output.TopRightStyle = newRight.TopLeftStyle; output.ObjSetTRStyle = newRight.ObjSetTLStyle; output.TopRightDoor = newRight.TopLeftDoor; } break; } } } else { output = input; } return output; }
public void SetWall(short tileX, short tileY, sbyte level, WallTile wall) { var off = GetOffset(tileX, tileY); WallsAt[level-1].Remove(off); if (wall.Segments > 0) { Walls[level - 1][off] = wall; WallsAt[level - 1].Add(off); } else { Walls[level - 1][off] = new WallTile(); } if (RealMode) WallsDirty = true; Redraw = true; }
public bool CheckWallValid(LotTilePos pos, WallTile wall) { if (pos.Level < 1 || pos.Level > ObjectsAt.Count || !ObjectsAt[pos.Level - 1].ContainsKey(pos.TileID)) return true; var objs = ObjectsAt[pos.Level - 1][pos.TileID]; foreach (var id in objs) { var obj = VM.GetObjectById(id); if (obj.WallChangeValid(wall, obj.Direction, false) != VMPlacementError.Success) return false; } return true; }
private static PatternReplaceCount SpreadOnto(WallTile[] walls, int x, int y, int inDir, byte[] map, int width, int height, Stack<Point> spread, ushort pattern, bool floorMode) { PatternReplaceCount filled = new PatternReplaceCount(false); var wall = walls[x + y * width]; if ((wall.Segments & WallSegments.HorizontalDiag) > 0 && (wall.TopRightStyle == 1 || floorMode)) { if (inDir < 2) { //bottom (bottom right pattern) if (!floorMode && wall.BottomLeftPattern != pattern) { filled.Add(wall.BottomLeftPattern); wall.BottomLeftPattern = pattern; } map[x + y * width] |= 1; } else { //top (bottom left pattern) if (!floorMode && wall.BottomRightPattern != pattern) { filled.Add(wall.BottomRightPattern); wall.BottomRightPattern = pattern; } map[x + y * width] |= 2; } if (!floorMode) walls[x + y * width] = wall; } else if ((wall.Segments & WallSegments.VerticalDiag) > 0 && (wall.TopRightStyle == 1 || floorMode)) { if (inDir > 0 && inDir < 3) { //left if (!floorMode && wall.BottomRightPattern != pattern) { filled.Add(wall.BottomRightPattern); wall.BottomRightPattern = pattern; } map[x + y * width] |= 1; } else { //right if (!floorMode && wall.BottomLeftPattern != pattern) { filled.Add(wall.BottomLeftPattern); wall.BottomLeftPattern = pattern; } map[x + y * width] |= 2; } if (!floorMode) walls[x + y * width] = wall; } else { map[x + y * width] = 3; } spread.Push(new Point(x, y)); return filled; }
public bool CheckWallValid(LotTilePos pos, WallTile wall) { var objs = SetToNextCache.GetObjectsAt(pos); if (objs == null) return true; foreach (var obj in objs) { if (obj.WallChangeValid(wall, obj.Direction, false) != VMPlacementError.Success) return false; } return true; }
public VMPlacementError WallChangeValid(WallTile wall, Direction direction, bool checkUnused) { var placeFlags = (WallPlacementFlags)ObjectData[(int)VMStackObjectVariable.WallPlacementFlags]; bool diag = ((wall.Segments & (WallSegments.HorizontalDiag | WallSegments.VerticalDiag)) > 0); if (diag && (placeFlags & WallPlacementFlags.DiagonalAllowed) == 0) return VMPlacementError.CantBeThroughWall; //does not allow diagonal and one is present else if (!diag && ((placeFlags & WallPlacementFlags.DiagonalRequired) > 0)) return VMPlacementError.MustBeOnDiagonal; //needs diagonal and one is not present int rotate = (DirectionToWallOff(direction) + 1) % 4; int rotPart = RotateWallSegs(wall.Segments, rotate); int useRotPart = RotateWallSegs(wall.OccupiedWalls, rotate); if (((int)placeFlags & rotPart) != ((int)placeFlags & 15)) return VMPlacementError.MustBeAgainstWall; //walls required are not there in this configuration //walls that we are attaching to must not be in use! if (checkUnused && ((int)placeFlags & useRotPart) > 0) return VMPlacementError.MustBeAgainstUnusedWall; if (((int)placeFlags & (rotPart << 8)) > 0) return VMPlacementError.CantBeThroughWall; //walls not allowed are there in this configuration return VMPlacementError.Success; }
public static WallTile Deserialize(BinaryReader reader) { var result = new WallTile(); result.Segments = (WallSegments)reader.ReadByte(); result.TopLeftPattern = reader.ReadUInt16(); result.TopRightPattern = reader.ReadUInt16(); result.BottomLeftPattern = reader.ReadUInt16(); result.BottomRightPattern = reader.ReadUInt16(); result.TopLeftStyle = reader.ReadUInt16(); result.TopRightStyle = reader.ReadUInt16(); return result; }
public static void SerializeInto(WallTile wall, BinaryWriter writer) { writer.Write((byte)wall.Segments); writer.Write(wall.TopLeftPattern); writer.Write(wall.TopRightPattern); writer.Write(wall.BottomLeftPattern); writer.Write(wall.BottomRightPattern); writer.Write(wall.TopLeftStyle); writer.Write(wall.TopRightStyle); }