public Error CanBuild(Position position, byte size, ICity city, bool requiresRoad) { var buildingPositions = tileLocator.ForeachMultitile(position.X, position.Y, size).ToArray(); var buildingNeighbors = tileLocator.ForeachRadius(position.X, position.Y, size, 1).ToArray(); var mainBuildingPositions = tileLocator.ForeachMultitile(city.MainBuilding).ToArray(); var roadsBeingBuiltOn = buildingPositions.Any(buildingPosition => world.Roads.IsRoad(buildingPosition.X, buildingPosition.Y)); if (!requiresRoad) { // Cant build on road if this building doesnt require roads return(roadsBeingBuiltOn ? Error.RoadDestroyUniquePath : Error.Ok); } if (roadsBeingBuiltOn) { // All structures should still have a valid path if we are building on top of a road foreach (var str in city) { if (str.IsMainBuilding || objectTypeFactory.IsObjectType("NoRoadRequired", str.Type)) { continue; } if (!HasPath(start: str.PrimaryPosition, startSize: str.Size, city: city, excludedPoints: buildingPositions)) { return(Error.RoadDestroyUniquePath); } } // All neighboring roads should have a different path foreach (var neighborPosition in buildingNeighbors) { if (mainBuildingPositions.Contains(neighborPosition) || !world.Roads.IsRoad(neighborPosition.X, neighborPosition.Y)) { continue; } if (!HasPath(start: neighborPosition, startSize: 1, city: city, excludedPoints: buildingPositions)) { return(Error.RoadDestroyUniquePath); } } } // There should be a road around this building foreach (var neighborPosition in buildingNeighbors) { bool hasStructure = world.Regions.GetObjectsInTile(neighborPosition.X, neighborPosition.Y) .Any(obj => obj is IStructure); if (hasStructure || !world.Roads.IsRoad(neighborPosition.X, neighborPosition.Y)) { continue; } if (roadsBeingBuiltOn && !HasPath(start: neighborPosition, startSize: 1, city: city, excludedPoints: buildingPositions)) { continue; } return(Error.Ok); } return(Error.RoadNotAround); }
private void RoadCreate(Session session, Packet packet) { var reply = new Packet(packet); uint x; uint y; uint cityId; try { cityId = packet.GetUInt32(); x = packet.GetUInt32(); y = packet.GetUInt32(); } catch (Exception) { ReplyError(session, packet, Error.Unexpected); return; } if (!world.Regions.IsValidXandY(x, y)) { ReplyError(session, packet, Error.Unexpected); return; } // Make sure there is no structure at this point that has no road requirement if (world.Regions.GetObjectsInTile(x, y).Any( s => s is IStructure && objectTypeFactory.IsStructureType("NoRoadRequired", (IStructure)s))) { ReplyError(session, packet, Error.StructureExists); return; } ICity city; locker.Lock(cityId, out city).Do(() => { if (city == null) { ReplyError(session, packet, Error.CityNotFound); return; } // Make sure user is building road within city walls if (tileLocator.TileDistance(city.PrimaryPosition, 1, new Position(x, y), 1) >= city.Radius) { ReplyError(session, packet, Error.NotWithinWalls); return; } world.Regions.LockRegion(x, y); // Make sure this tile is not already a road if (world.Roads.IsRoad(x, y)) { world.Regions.UnlockRegion(x, y); ReplyError(session, packet, Error.RoadAlreadyExists); return; } // Make sure there is a road next to this tile bool hasRoad = false; foreach (var position in tileLocator.ForeachRadius(x, y, 1, false)) { if ((world.Roads.IsRoad(position.X, position.Y) && !world.Regions.GetObjectsInTile(position.X, position.Y).Any(s => s is IStructure && s != city.MainBuilding))) { hasRoad = true; break; } } if (!hasRoad) { world.Regions.UnlockRegion(x, y); ReplyError(session, packet, Error.RoadNotAround); return; } if (objectTypeFactory.IsTileType("TileResource", world.Regions.GetTileType(x, y))) { world.Regions.UnlockRegion(x, y); ReplyError(session, packet, Error.TileMismatch); return; } world.Roads.CreateRoad(x, y, city.RoadTheme); world.Regions.UnlockRegion(x, y); session.Write(reply); }); }