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)); }
public bool SetFloor(short tileX, short tileY, sbyte level, FloorTile floor, bool force) { //returns false on failure var offset = GetOffset(tileX, tileY); if (!force) { //first check if we're supported if (level > 1 && !Supported[level - 2][offset]) return false; //check if objects need/don't need floors if (!Context.CheckFloorValid(LotTilePos.FromBigTile((short)tileX, (short)tileY, level), floor)) return false; } Floors[level-1][offset] = floor; if (RealMode) FloorsDirty = true; Redraw = true; return true; }
public bool CheckFloorValid(LotTilePos pos, FloorTile floor) { 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.FloorChangeValid(floor, pos.Level) != VMPlacementError.Success) return false; } return true; }
public bool CheckFloorValid(LotTilePos pos, FloorTile floor) { var objs = SetToNextCache.GetObjectsAt(pos); if (objs == null) return true; foreach (var obj in objs) { if (obj.FloorChangeValid(floor, pos.Level) != VMPlacementError.Success) return false; } return true; }
public VMPlacementError FloorChangeValid(FloorTile floor, sbyte level) { var placeFlags = (VMPlacementFlags)ObjectData[(int)VMStackObjectVariable.PlacementFlags]; if (floor.Pattern == 65535) { if ((placeFlags & (VMPlacementFlags.AllowOnPool | VMPlacementFlags.RequirePool)) == 0) return VMPlacementError.CantPlaceOnWater; } else { if ((placeFlags & VMPlacementFlags.RequirePool) > 0) return VMPlacementError.MustPlaceOnPool; if (floor.Pattern == 63354) { if ((placeFlags & (VMPlacementFlags.OnWater | VMPlacementFlags.RequireWater)) == 0) return VMPlacementError.CantPlaceOnWater; } else { if ((placeFlags & VMPlacementFlags.RequireWater) > 0) return VMPlacementError.MustPlaceOnWater; if (floor.Pattern == 0) { if (level == 1) { if ((placeFlags & VMPlacementFlags.OnTerrain) == 0) return VMPlacementError.NotAllowedOnTerrain; } else { if ((placeFlags & VMPlacementFlags.InAir) == 0 && Object.OBJ.LevelOffset == 0) return VMPlacementError.CantPlaceInAir; //TODO: special hack check that determines if we need can add/remove a tile to fulfil this if LevelOffset > 0 } } else { if ((placeFlags & VMPlacementFlags.OnFloor) == 0 && ((Object.OBJ.LevelOffset == 0) || (placeFlags & VMPlacementFlags.InAir) == 0)) return VMPlacementError.NotAllowedOnFloor; } } } return VMPlacementError.Success; }