Beispiel #1
0
        public void ObjectUpdateEvent_LocksBothPreviousAndCurrentRegions(
            ISimpleGameObject simpleGameObject,
            [Frozen] IRegionLocator regionLocator,
            IRegion region0,
            IRegion region1,
            [Frozen] ITileLocator tileLocator,
            RegionManager regionManager)
        {
            simpleGameObject.InWorld.Returns(true);
            simpleGameObject.Size.Returns <byte>(11);
            simpleGameObject.PrimaryPosition.Returns(new Position(1, 2));

            regionManager.AddRegion(region0);
            regionManager.AddRegion(region1);

            regionLocator.GetRegionIndex(1, 9).Returns <ushort>(0);
            regionLocator.GetRegionIndex(2, 9).Returns <ushort>(1);

            tileLocator.ForeachMultitile(1, 2, 11).Returns(new[]
            {
                new Position(1, 9)
            });

            tileLocator.ForeachMultitile(2, 3, 11).Returns(new[]
            {
                new Position(2, 9)
            });

            regionManager.UpdateObject(simpleGameObject, 2, 3);

            region0.Received(1).EnterWriteLock();
            region1.Received(1).EnterWriteLock();
            region0.Received(1).ExitWriteLock();
            region1.Received(1).ExitWriteLock();
        }
Beispiel #2
0
        public void Remove_WhenATileIsInInvalidRegion_RemovesFromAllOtherTilesAndIgnoresInvalidTile(
            ISimpleGameObject simpleGameObject,
            [Frozen] IRegionLocator regionLocator,
            IRegion region0,
            [Frozen] ITileLocator tileLocator,
            RegionManager regionManager)
        {
            simpleGameObject.InWorld.Returns(true);
            simpleGameObject.PrimaryPosition.Returns(new Position(1, 2));

            regionLocator.GetRegionIndex(1, 1).Returns <ushort>(0);
            regionLocator.GetRegionIndex(2, 1).Returns <ushort>(1);

            tileLocator.ForeachMultitile(0, 0, 0).ReturnsForAnyArgs(new[]
            {
                new Position(1, 1),
                new Position(2, 1),
            });

            regionManager.AddRegion(region0);

            regionManager.Remove(simpleGameObject);

            region0.Received(1).Remove(simpleGameObject, 1, 2);
            region0.Received(1).RemoveObjectFromTile(simpleGameObject, 1, 1);
        }
Beispiel #3
0
        public void Add_ShouldAddObjectToAllTiles(
            ISimpleGameObject simpleGameObject,
            [Frozen] IRegionLocator regionLocator,
            IRegion region0,
            IRegion region1,
            IRegion region2,
            [Frozen] ITileLocator tileLocator,
            RegionManager regionManager)
        {
            simpleGameObject.PrimaryPosition.Returns(new Position(1, 2));
            regionLocator.GetRegionIndex(0, 0).ReturnsForAnyArgs <ushort>(2);

            regionLocator.GetRegionIndex(1, 1).Returns <ushort>(0);
            regionLocator.GetRegionIndex(1, 2).Returns <ushort>(0);
            regionLocator.GetRegionIndex(2, 1).Returns <ushort>(1);

            tileLocator.ForeachMultitile(simpleGameObject).Returns(new[]
            {
                new Position(1, 1),
                new Position(1, 2),
                new Position(2, 1),
            });

            regionManager.AddRegion(region0);
            regionManager.AddRegion(region1);
            regionManager.AddRegion(region2);

            regionManager.Add(simpleGameObject);

            region0.Received(1).AddObjectToTile(simpleGameObject, 1, 1);
            region0.Received(1).AddObjectToTile(simpleGameObject, 1, 2);
            region1.Received(1).AddObjectToTile(simpleGameObject, 2, 1);
            region2.DidNotReceive().AddObjectToTile(Arg.Any <ISimpleGameObject>(), Arg.Any <uint>(), Arg.Any <uint>());
        }
Beispiel #4
0
        public void Remove_ProperlyLocksRegions(
            ISimpleGameObject simpleGameObject,
            [Frozen] IRegionLocator regionLocator,
            IRegion region0,
            IRegion region1,
            IRegion region2,
            [Frozen] ITileLocator tileLocator,
            RegionManager regionManager)
        {
            simpleGameObject.InWorld.Returns(true);
            regionLocator.GetRegionIndex(0, 0).ReturnsForAnyArgs <ushort>(2);

            regionLocator.GetRegionIndex(1, 1).Returns <ushort>(0);
            regionLocator.GetRegionIndex(1, 2).Returns <ushort>(0);
            regionLocator.GetRegionIndex(2, 1).Returns <ushort>(1);

            tileLocator.ForeachMultitile(0, 0, 0).ReturnsForAnyArgs(new[]
            {
                new Position(1, 1),
                new Position(2, 1),
            });

            regionManager.AddRegion(region0);
            regionManager.AddRegion(region1);
            regionManager.AddRegion(region2);

            regionManager.Remove(simpleGameObject);

            region0.Received(1).EnterWriteLock();
            region1.Received(1).EnterWriteLock();
            region0.Received(1).ExitWriteLock();
            region1.Received(1).ExitWriteLock();
            region2.DidNotReceive().EnterWriteLock();
        }
Beispiel #5
0
        public void Add_WhenSomeTilesAreInInvalidRegion_ShouldIgnoreRegions(
            ISimpleGameObject simpleGameObject,
            [Frozen] IRegionLocator regionLocator,
            IRegion region0,
            [Frozen] ITileLocator tileLocator,
            RegionManager regionManager)
        {
            simpleGameObject.PrimaryPosition.Returns(new Position(1, 1));
            regionLocator.GetRegionIndex(0, 0).ReturnsForAnyArgs <ushort>(2);

            regionLocator.GetRegionIndex(1, 1).Returns <ushort>(0);
            regionLocator.GetRegionIndex(2, 1).Returns <ushort>(1);

            tileLocator.ForeachMultitile(simpleGameObject).Returns(new[]
            {
                new Position(1, 1),
                new Position(2, 1),
            });

            regionManager.AddRegion(region0);

            regionManager.Add(simpleGameObject);

            region0.Received(1).AddObjectToTile(simpleGameObject, 1, 1);
        }
Beispiel #6
0
        public void Execute_WhenAStructureTileIsNotValid_ReturnsError(
            [Frozen] IWorld world,
            [Frozen] ITileLocator tileLocator,
            Fixture fixture)
        {
            var action = new StructureBuildActiveActionExecuteBuilder(fixture).Build();

            world.Regions.IsValidXandY(1, 1).Returns(true);
            world.Regions.IsValidXandY(1, 2).Returns(false);
            tileLocator.ForeachMultitile(0, 0, 0).ReturnsForAnyArgs(new[] { new Position(1, 1), new Position(1, 2) });

            action.Execute().Should().Be(Error.ActionInvalid);
        }
Beispiel #7
0
        public void LockRegions_WhenCalledWithInvalidPosition_IgnoresInvalidRegion(
            [Frozen] ITileLocator tileLocator,
            [Frozen] IRegionLocator regionLocator,
            RegionManager regionManager)
        {
            var lockedRegions = new List <IRegion>();

            regionLocator.GetRegionIndex(0, 0).ReturnsForAnyArgs <ushort>(0);

            tileLocator.ForeachMultitile(10, 20, 3).Returns(new[]
            {
                new Position(1, 1),
            });

            regionManager.LockMultitileRegions(10, 20, 3);

            lockedRegions.Should().BeEmpty();
        }
Beispiel #8
0
        public void Execute_WhenAllStructureTilesAreValid_ReturnsOk(
            [Frozen] IWorld world,
            [Frozen] ITileLocator tileLocator,
            [Frozen] IStructureBaseStats structureBaseStats,
            Fixture fixture)
        {
            var action = new StructureBuildActiveActionExecuteBuilder(fixture).Build();

            structureBaseStats.Size.Returns <byte>(11);

            tileLocator.ForeachMultitile(action.X, action.Y, 11).Returns(new[] { new Position(1, 1), new Position(1, 2) });

            world.Regions.IsValidXandY(Arg.Any <uint>(), Arg.Any <uint>()).Returns(false);
            world.Regions.IsValidXandY(1, 1).Returns(true);
            world.Regions.IsValidXandY(1, 2).Returns(true);

            action.Execute().Should().Be(Error.Ok);
        }
Beispiel #9
0
        public void Execute_WhenAStructureTileIsAlreadyOccupied_ReturnsError(
            [Frozen] IWorld world,
            [Frozen] ITileLocator tileLocator,
            [Frozen] ICity city,
            [Frozen] IStructureBaseStats structureBaseStats,
            Fixture fixture)
        {
            var action = new StructureBuildActiveActionExecuteBuilder(fixture).Build();

            structureBaseStats.Size.Returns <byte>(11);

            tileLocator.ForeachMultitile(action.X, action.Y, 11).Returns(new[] { new Position(1, 1), new Position(1, 2) });
            world.Regions.GetObjectsInTile(1, 1).Returns(new List <ISimpleGameObject>());
            world.Regions.GetObjectsInTile(1, 2).Returns(new List <ISimpleGameObject> {
                Substitute.For <IStructure>()
            });

            action.Execute().Should().Be(Error.StructureExists);
        }
Beispiel #10
0
        public void Execute_WhenAStructureTileIsOutOfCityRadius_ReturnsError(
            [Frozen] IWorld world,
            [Frozen] ITileLocator tileLocator,
            [Frozen] ICity city,
            [Frozen] IStructureBaseStats structureBaseStats,
            Fixture fixture)
        {
            var action = new StructureBuildActiveActionExecuteBuilder(fixture).Build();

            structureBaseStats.Size.Returns <byte>(11);

            tileLocator.ForeachMultitile(action.X, action.Y, 11).Returns(new[] { new Position(1, 1), new Position(1, 2) });
            tileLocator.TileDistance(city.PrimaryPosition, 1, Arg.Is <Position>(p => p.X == 1 && p.Y == 1), 1).Returns(5);
            tileLocator.TileDistance(city.PrimaryPosition, 1, Arg.Is <Position>(p => p.X == 1 && p.Y == 2), 1).Returns(6);

            city.Radius.Returns <byte>(6);

            action.Execute().Should().Be(Error.NotWithinWalls);
        }
Beispiel #11
0
        public void LockRegions_WhenCalledWithMultipleRegions_ShouldLockRegionInProperOrder(
            [Frozen] ITileLocator tileLocator,
            IRegion region1,
            IRegion region2,
            IRegion region3,
            IRegion region4,
            [Frozen] IRegionLocator regionLocator,
            RegionManager regionManager)
        {
            var lockedRegions = new List <IRegion>();

            region1.When(p => p.EnterWriteLock()).Do(x => lockedRegions.Add(region1));
            region2.When(p => p.EnterWriteLock()).Do(x => lockedRegions.Add(region2));
            region3.When(p => p.EnterWriteLock()).Do(x => lockedRegions.Add(region3));
            region4.When(p => p.EnterWriteLock()).Do(x => lockedRegions.Add(region4));

            regionManager.AddRegion(region1);
            regionManager.AddRegion(region2);
            regionManager.AddRegion(region3);
            regionManager.AddRegion(region4);

            regionLocator.GetRegionIndex(0, 0).ReturnsForAnyArgs <ushort>(3);
            regionLocator.GetRegionIndex(0, 1).Returns <ushort>(0);
            regionLocator.GetRegionIndex(0, 2).Returns <ushort>(0);
            regionLocator.GetRegionIndex(1, 1).Returns <ushort>(1);
            regionLocator.GetRegionIndex(2, 1).Returns <ushort>(2);

            tileLocator.ForeachMultitile(10, 20, 3).Returns(new[]
            {
                new Position(1, 1),
                new Position(0, 1),
                new Position(2, 1),
                new Position(0, 2),
            });

            var result = regionManager.LockMultitileRegions(10, 20, 3);

            lockedRegions.Should().Equal(region1, region2, region3);
            result.Should().Equal(new ushort[] { 0, 1, 2 });
        }
Beispiel #12
0
        public void Remove_RemovesObjectFromAllTiles(
            ISimpleGameObject simpleGameObject,
            [Frozen] IRegionLocator regionLocator,
            IRegion region0,
            IRegion region1,
            IRegion region2,
            [Frozen] ITileLocator tileLocator,
            RegionManager regionManager)
        {
            simpleGameObject.InWorld.Returns(true);
            simpleGameObject.PrimaryPosition.Returns(new Position(1, 2));
            simpleGameObject.Size.Returns <byte>(10);
            regionLocator.GetRegionIndex(0, 0).ReturnsForAnyArgs <ushort>(2);

            regionLocator.GetRegionIndex(1, 1).Returns <ushort>(0);
            regionLocator.GetRegionIndex(1, 2).Returns <ushort>(0);
            regionLocator.GetRegionIndex(2, 1).Returns <ushort>(1);

            tileLocator.ForeachMultitile(1, 2, 10).Returns(new[]
            {
                new Position(1, 1),
                new Position(1, 2),
                new Position(2, 1),
            });

            regionManager.AddRegion(region0);
            regionManager.AddRegion(region1);
            regionManager.AddRegion(region2);

            regionManager.Remove(simpleGameObject);

            region0.Received(1).Remove(simpleGameObject, 1, 2);
            region0.Received(1).RemoveObjectFromTile(simpleGameObject, 1, 1);
            region0.Received(1).RemoveObjectFromTile(simpleGameObject, 1, 2);
            region1.Received(1).RemoveObjectFromTile(simpleGameObject, 2, 1);
            region2.DidNotReceive().RemoveObjectFromTile(Arg.Any <ISimpleGameObject>(), Arg.Any <uint>(), Arg.Any <uint>());
        }
Beispiel #13
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);
        }
Beispiel #14
0
 public bool TooCloseToCities(Position position, byte size)
 {
     return(tileLocator.ForeachMultitile(position.X, position.Y, size)
            .SelectMany(eachPosition => tileLocator.ForeachTile(eachPosition.X, eachPosition.Y, MIN_DISTANCE_AWAY_FROM_CITIES))
            .Any(positionToCheck => cityLocationsByPosition.Contains(positionToCheck)));
 }
Beispiel #15
0
 private IEnumerable <Position> GetMultitileRegionIds(uint x, uint y, byte size)
 {
     return(tileLocator.ForeachMultitile(x, y, size));
 }
Beispiel #16
0
        public override Error Execute()
        {
            ICity city;

            if (!world.TryGetObjects(cityId, out city))
            {
                return(Error.ObjectNotFound);
            }

            var maxConcurrentUpgradesResult = formula.CityMaxConcurrentBuildActions(type, ActionId, city, objectTypeFactory);

            if (maxConcurrentUpgradesResult != Error.Ok)
            {
                return(maxConcurrentUpgradesResult);
            }

            var structureBaseStats = structureCsvFactory.GetBaseStats(type, level);

            var lockedRegions = world.Regions.LockMultitileRegions(X, Y, structureBaseStats.Size);

            foreach (var position in tileLocator.ForeachMultitile(X, Y, structureBaseStats.Size))
            {
                var tileType = world.Regions.GetTileType(position.X, position.Y);
                // tile requirement
                if (!string.IsNullOrEmpty(tileRequirement) && !objectTypeFactory.IsTileType(tileRequirement, tileType))
                {
                    world.Regions.UnlockRegions(lockedRegions);
                    return(Error.TileMismatch);
                }

                // Only allow buildings that require resource tile to built on them
                if (tileRequirement != "TileResource" && objectTypeFactory.IsTileType("TileResource", tileType))
                {
                    world.Regions.UnlockRegions(lockedRegions);
                    return(Error.TileMismatch);
                }

                // dont allow building on edge of world
                if (!world.Regions.IsValidXandY(position.X, position.Y))
                {
                    world.Regions.UnlockRegions(lockedRegions);
                    return(Error.ActionInvalid);
                }

                // radius requirements
                if (tileLocator.TileDistance(city.PrimaryPosition, 1, position, 1) >= city.Radius)
                {
                    world.Regions.UnlockRegions(lockedRegions);
                    return(Error.NotWithinWalls);
                }

                // check if tile is occupied
                if (world.Regions.GetObjectsInTile(position.X, position.Y).Any(obj => obj is IStructure))
                {
                    world.Regions.UnlockRegions(lockedRegions);
                    return(Error.StructureExists);
                }
            }

            // cost requirement
            cost = formula.StructureCost(city, structureBaseStats);
            if (!city.Resource.HasEnough(cost))
            {
                world.Regions.UnlockRegions(lockedRegions);
                return(Error.ResourceNotEnough);
            }

            // layout requirement
            if (!requirementCsvFactory.GetLayoutRequirement(type, level).Validate(WorkerObject as IStructure, type, X, Y, structureBaseStats.Size))
            {
                world.Regions.UnlockRegions(lockedRegions);
                return(Error.LayoutNotFullfilled);
            }

            // check for road requirements
            var requiresRoad = !objectTypeFactory.IsObjectType("NoRoadRequired", type);
            var canBuild     = roadPathFinder.CanBuild(new Position(X, Y), structureBaseStats.Size, city, requiresRoad);

            if (canBuild != Error.Ok)
            {
                world.Regions.UnlockRegions(lockedRegions);
                return(canBuild);
            }

            // add structure to the map
            IStructure structure = city.CreateStructure(type, 0, X, Y);

            city.BeginUpdate();
            city.Resource.Subtract(cost);
            city.EndUpdate();

            structure.BeginUpdate();

            if (!world.Regions.Add(structure))
            {
                city.ScheduleRemove(structure, false);
                city.BeginUpdate();
                city.Resource.Add(cost);
                city.EndUpdate();
                structure.EndUpdate();

                world.Regions.UnlockRegions(lockedRegions);
                return(Error.MapFull);
            }

            structure.EndUpdate();

            callbackProcedure.OnStructureUpgrade(structure);

            structureId = structure.ObjectId;

            // add to queue for completion
            var buildTime = formula.BuildTime(structureBaseStats.BuildTime, city, city.Technologies);

            endTime   = SystemClock.Now.AddSeconds(CalculateTime(buildTime));
            BeginTime = SystemClock.Now;

            city.References.Add(structure, this);

            world.Regions.UnlockRegions(lockedRegions);
            return(Error.Ok);
        }