예제 #1
0
        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);
        }
예제 #2
0
        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);
            });
        }