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