Exemple #1
0
        private static Vector2D?FindClosestPosition(Vector2D position)
        {
            var physicsSpace   = ServerWorldService.GetPhysicsSpace();
            var collisionGroup = CollisionGroup.Default;

            if (IsValidPosition(
                    // round position
                    position.ToVector2Ushort().ToVector2D()))
            {
                // can teleport right there
                return(position);
            }

            // check nearby tiles
            var tile = ServerWorldService.GetTile(position.ToVector2Ushort());

            foreach (var neighborTile in tile.EightNeighborTiles)
            {
                if (!neighborTile.IsValidTile)
                {
                    continue;
                }

                var neighborTilePosition = neighborTile.Position.ToVector2D();
                if (IsValidPosition(neighborTilePosition))
                {
                    return(neighborTilePosition);
                }
            }

            return(null);

            // Local function for checking if the position is valid.
            bool IsValidPosition(Vector2D pos)
            {
                using var objectsNearby = physicsSpace.TestRectangle(
                          // include some padding, otherwise the check will include border-objects
                          position: pos + (0.01, 0.01),
                          size: (0.98, 0.98),
                          collisionGroup: collisionGroup,
                          sendDebugEvent: false);
                if (objectsNearby.Count > 0)
                {
                    return(false);
                }

                var posTile = Server.World.GetTile(pos.ToVector2Ushort());

                return(ServerCharacterSpawnHelper.IsValidSpawnTile(posTile,
                                                                   checkNeighborTiles: false));
            }
        }
Exemple #2
0
        private static bool ServerCheckCanSpawn(IProtoWorldObject protoObjectToSpawn, Vector2Ushort spawnPosition)
        {
            switch (protoObjectToSpawn)
            {
            case IProtoCharacterMob _:
                return(ServerCharacterSpawnHelper.IsPositionValidForCharacterSpawn(spawnPosition.ToVector2D(),
                                                                                   isPlayer: false));

            case IProtoStaticWorldObject protoStaticWorldObject:
                return(protoStaticWorldObject.CheckTileRequirements(spawnPosition,
                                                                    character: null,
                                                                    logErrors: false));

            default:
                throw new Exception("Unknown object type to spawn: " + protoObjectToSpawn);
            }
        }
Exemple #3
0
        protected virtual bool ServerIsValidSpawnPosition(Vector2D worldPosition)
        {
            const double noObstaclesCheckRadius = 1.5;
            var          physicsSpace           = Server.World.GetPhysicsSpace();

            foreach (var _ in physicsSpace.TestCircle(worldPosition,
                                                      radius: noObstaclesCheckRadius,
                                                      CollisionGroups.Default,
                                                      sendDebugEvent: false).EnumerateAndDispose())
            {
                // position is not valid for spawning
                return(false);
            }

            return(ServerCharacterSpawnHelper.IsValidSpawnTile(
                       Api.Server.World.GetTile(worldPosition.ToVector2Ushort()),
                       checkNeighborTiles: true));
        }
        /// <summary>
        /// Server spawn callback for mob.
        /// </summary>
        /// <param name="trigger">Trigger leading to this spawn.</param>
        /// <param name="zone">Server zone instance.</param>
        /// <param name="protoMob">Prototype of character mob object to spawn.</param>
        /// <param name="tilePosition">Position to try spawn at.</param>
        protected virtual IGameObjectWithProto ServerSpawnMob(
            IProtoTrigger trigger,
            IServerZone zone,
            IProtoCharacterMob protoMob,
            Vector2Ushort tilePosition)
        {
            var worldPosition = tilePosition.ToVector2D();

            if (!ServerCharacterSpawnHelper.IsPositionValidForCharacterSpawn(worldPosition,
                                                                             isPlayer: false))
            {
                // position is not valid for spawning
                return(null);
            }

            return(Server.Characters.SpawnCharacter(
                       protoMob,
                       worldPosition));
        }
Exemple #5
0
        private static bool ServerCheckCanSpawn(IProtoWorldObject protoObjectToSpawn, Vector2Ushort spawnPosition)
        {
            return(protoObjectToSpawn switch
            {
                IProtoCharacterMob
                => ServerCharacterSpawnHelper.IsPositionValidForCharacterSpawn(
                    spawnPosition.ToVector2D(),
                    isPlayer: false) &&
                !LandClaimSystem.SharedIsLandClaimedByAnyone(spawnPosition),

                IProtoStaticWorldObject protoStaticWorldObject
                // Please note: land claim check must be integrated in the object tile requirements
                => protoStaticWorldObject.CheckTileRequirements(
                    spawnPosition,
                    character: null,
                    logErrors: false),

                _ => throw new ArgumentOutOfRangeException("Unknown object type to spawn: " + protoObjectToSpawn)
            });
        public static void ServerTrySpawnMobsCustom(
            IProtoCharacter protoMob,
            ICollection <ICharacter> spawnedCollection,
            int countToSpawn,
            RectangleInt excludeBounds,
            int maxSpawnDistanceFromExcludeBounds,
            double noObstaclesCheckRadius,
            int maxAttempts)
        {
            if (countToSpawn <= 0)
            {
                return;
            }

            var spawnBounds = excludeBounds.Inflate(maxSpawnDistanceFromExcludeBounds,
                                                    maxSpawnDistanceFromExcludeBounds);
            var physicsSpace = Api.Server.World.GetPhysicsSpace();

            while (maxAttempts-- > 0)
            {
                var position = new Vector2D(spawnBounds.Left + RandomHelper.NextDouble() * spawnBounds.Width,
                                            spawnBounds.Bottom + RandomHelper.NextDouble() * spawnBounds.Height);
                if (IsTooClose(position))
                {
                    continue;
                }

                var character = ServerTrySpawnMob(position);
                if (character is null)
                {
                    // cannot spawn there
                    continue;
                }

                spawnedCollection.Add(character);

                countToSpawn--;
                if (countToSpawn == 0)
                {
                    return;
                }
            }

            bool IsTooClose(in Vector2D position)
            => position.X >= excludeBounds.X &&
            position.Y >= excludeBounds.Y &&
            position.X < excludeBounds.X + excludeBounds.Width &&
            position.Y < excludeBounds.Y + excludeBounds.Height;

            ICharacter ServerTrySpawnMob(Vector2D worldPosition)
            {
                foreach (var _ in physicsSpace.TestCircle(worldPosition,
                                                          radius: noObstaclesCheckRadius,
                                                          CollisionGroups.Default,
                                                          sendDebugEvent: false).EnumerateAndDispose())
                {
                    // position is not valid for spawning
                    return(null);
                }

                if (!ServerCharacterSpawnHelper.IsValidSpawnTile(
                        Api.Server.World.GetTile(worldPosition.ToVector2Ushort()),
                        checkNeighborTiles: true))
                {
                    return(null);
                }

                return(Api.Server.Characters.SpawnCharacter(protoMob,
                                                            worldPosition));
            }
        }
Exemple #7
0
        public static void ServerSpawnBossMinionsOnDeath(
            Vector2Ushort epicenterPosition,
            double bossDifficultyCoef,
            IProtoCharacter minionProto,
            int minionsDefaultCount,
            double minionsRadius)
        {
            var countToSpawnRemains = minionsDefaultCount;

            // apply difficulty coefficient
            countToSpawnRemains = (int)Math.Ceiling(countToSpawnRemains * bossDifficultyCoef);

            var attemptsRemains = 3000;

            while (countToSpawnRemains > 0)
            {
                attemptsRemains--;
                if (attemptsRemains <= 0)
                {
                    // attempts exceeded
                    return;
                }

                // calculate random distance from the explosion epicenter
                var distance = RandomHelper.Range(2, minionsRadius);

                // ensure we spawn more objects closer to the epicenter
                var spawnProbability = 1 - (distance / minionsRadius);
                spawnProbability = Math.Pow(spawnProbability, 1.25);
                if (!RandomHelper.RollWithProbability(spawnProbability))
                {
                    // random skip
                    continue;
                }

                var angle         = RandomHelper.NextDouble() * MathConstants.DoublePI;
                var spawnPosition = new Vector2Ushort(
                    (ushort)(epicenterPosition.X + distance * Math.Cos(angle)),
                    (ushort)(epicenterPosition.Y + distance * Math.Sin(angle)));

                if (ServerTrySpawnMinion(spawnPosition))
                {
                    // spawned successfully!
                    countToSpawnRemains--;
                }
            }

            bool ServerTrySpawnMinion(Vector2Ushort spawnPosition)
            {
                var worldPosition = spawnPosition.ToVector2D();

                if (!ServerCharacterSpawnHelper.IsPositionValidForCharacterSpawn(worldPosition,
                                                                                 isPlayer: false))
                {
                    // position is not valid for spawning
                    return(false);
                }

                var spawnedCharacter = ServerCharacters.SpawnCharacter(minionProto, worldPosition);

                return(spawnedCharacter is not null);
            }
        }