private static Vector2Ushort?TryFindZoneSpawnPosition(
            ICharacter character,
            IServerZone spawnZone,
            Random random,
            bool isRespawn)
        {
            var characterDeathPosition = Vector2Ushort.Zero;

            if (isRespawn && character.ProtoCharacter is PlayerCharacter)
            {
                var privateState = PlayerCharacter.GetPrivateState(character);
                if (!privateState.LastDeathTime.HasValue)
                {
                    return(null);
                }

                characterDeathPosition = privateState.LastDeathPosition;
            }

            var restrictedZone = ZoneSpecialConstructionRestricted.Instance.ServerZoneInstance;

            for (var attempt = 0; attempt < SpawnInZoneAttempts; attempt++)
            {
                var randomPosition = spawnZone.GetRandomPosition(random);

                if (isRespawn)
                {
                    var sqrDistance = randomPosition.TileSqrDistanceTo(characterDeathPosition);
                    if (sqrDistance > MaxDistanceWhenRespawnSqr ||
                        sqrDistance < MinDistanceWhenRespawnSqr)
                    {
                        // too close or too far for the respawn
                        continue;
                    }
                }

                if (restrictedZone.IsContainsPosition(randomPosition))
                {
                    // the position is inside the restricted zone
                    continue;
                }

                if (!LandClaimSystem.SharedIsPositionInsideOwnedOrFreeArea(randomPosition,
                                                                           character,
                                                                           requireFactionPermission: false))
                {
                    // the land is claimed by another player
                    continue;
                }

                if (ServerCharacterSpawnHelper.IsPositionValidForCharacterSpawn(randomPosition.ToVector2D(),
                                                                                isPlayer: true))
                {
                    // valid position found
                    return(randomPosition);
                }
            }

            return(null);
        }
        private static Vector2Ushort?TryFindZoneSpawnPosition(
            ICharacter character,
            IServerZone spawnZone,
            Random random,
            bool isRespawn)
        {
            var characterDeathPosition = Vector2Ushort.Zero;

            if (isRespawn && character.ProtoCharacter is PlayerCharacter)
            {
                characterDeathPosition = PlayerCharacter.GetPrivateState(character)
                                         .LastDeathPosition;
            }

            for (var attempt = 0; attempt < SpawnInZoneAttempts; attempt++)
            {
                var randomPosition = spawnZone.GetRandomPosition(random);

                if (isRespawn)
                {
                    var sqrDistance = randomPosition.TileSqrDistanceTo(characterDeathPosition);
                    if (sqrDistance > MaxDistanceWhenRespawnSqr ||
                        sqrDistance < MinDistanceWhenRespawnSqr)
                    {
                        // too close or too far for the respawn
                        continue;
                    }
                }

                if (LandClaimSystem.SharedGetAreaAtPosition(randomPosition) is ILogicObject area &&
                    !LandClaimSystem.ServerIsOwnedArea(area, character))
                {
                    // the land is claimed by another player
                    continue;
                }

                if (ServerCharacterSpawnHelper.IsPositionValidForCharacterSpawn(randomPosition.ToVector2D(),
                                                                                isPlayer: true))
                {
                    // valid position found
                    return(randomPosition);
                }
            }

            return(null);
        }
예제 #3
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);
            if (countToSpawnRemains < 2)
            {
                countToSpawnRemains = 2;
            }

            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);
            }
        }