예제 #1
0
        public static void OnCharacterDeath(ICharacter deadCharacter)
        {
            var publicState = deadCharacter.GetPublicState <ICharacterPublicState>();

            if (!publicState.IsDead)
            {
                publicState.CurrentStats.ServerSetHealthCurrent(0);
                return;
            }

            // recreate physics (as dead character doesn't have any physics)
            deadCharacter.ProtoCharacter.SharedCreatePhysics(deadCharacter);

            if (deadCharacter.ProtoCharacter is IProtoCharacterMob protoCharacterMob)
            {
                Api.SafeInvoke(() => CharacterDeath?.Invoke(deadCharacter));
                protoCharacterMob.ServerOnDeath(deadCharacter);
                return;
            }

            // player character death
            // remember the death position (useful for the respawn)
            var privateState = PlayerCharacter.GetPrivateState(deadCharacter);

            privateState.LastDeathPosition = deadCharacter.TilePosition;
            privateState.LastDeathTime     = Api.Server.Game.FrameTime;
            ServerTimersSystem.AddAction(
                delaySeconds: PlayerTeleportToGraveyardDelaySeconds,
                () =>
            {
                if (!publicState.IsDead)
                {
                    // player has already respawned
                    return;
                }

                CharacterDespawnSystem.ServerTeleportPlayerCharacterToServiceArea(deadCharacter);
                CharacterRespawnSystem.ServerRemoveStatusEffectsOnRespawn(deadCharacter);
            });

            var isPvPdeath = CharacterDamageTrackingSystem.ServerGetPvPdamagePercent(deadCharacter)
                             >= 0.5;

            // register death (required even if the player is not a newbie)
            NewbieProtectionSystem.ServerRegisterDeath(deadCharacter,
                                                       isPvPdeath,
                                                       out var shouldSufferDeathConsequences);

            if (shouldSufferDeathConsequences)
            {
                DropPlayerLoot(deadCharacter);
            }
            else
            {
                Api.Logger.Important("Player character is dead - newbie PvP case, no loot drop or other consequences",
                                     deadCharacter);
            }

            Api.SafeInvoke(() => CharacterDeath?.Invoke(deadCharacter));
        }
예제 #2
0
        // "Graveyard" is a technical area in the bottom right corner of the map.
        private static void TeleportDeadPlayerCharacterToGraveyard(ICharacter character)
        {
            if (character.IsNpc)
            {
                // only player characters are teleported to graveyard
                return;
            }

            var publicState = character.GetPublicState <ICharacterPublicState>();

            if (!publicState.IsDead)
            {
                // player has been respawned
                return;
            }

            VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true);

            // disable the visual scope so the player cannot not see anyone and nobody could see the player
            Api.Server.Characters.SetViewScopeMode(character, isEnabled: false);
            var graveyardPosition = ServerGetGraveyardPosition();

            if (character.TilePosition != graveyardPosition)
            {
                ServerWorld.SetPosition(character, (Vector2D)graveyardPosition);
            }

            CharacterRespawnSystem.ServerRemoveInvalidStatusEffects(character);
        }
        // "Graveyard" is a technical area in the bottom right corner of the map.
        private static void TeleportDeadPlayerCharacterToGraveyard(ICharacter character)
        {
            if (character.IsNpc)
            {
                // only player characters are teleported to graveyard
                return;
            }

            var publicState = character.GetPublicState <ICharacterPublicState>();

            if (!publicState.IsDead)
            {
                // player has been respawned
                return;
            }

            // disable the visual scope so the player cannot not see anyone and nobody could see the player
            Api.Server.Characters.SetViewScopeMode(character, isEnabled: false);
            var world       = Api.Server.World;
            var worldBounds = world.WorldBounds;

            // teleport to bottom right corner of the map
            var position = new Vector2Ushort((ushort)(worldBounds.Offset.X + worldBounds.Size.X - 1),
                                             (ushort)(worldBounds.Offset.Y + 1));

            if (character.TilePosition != position)
            {
                world.SetPosition(character, (Vector2D)position);
            }

            CharacterRespawnSystem.ServerRemoveInvalidStatusEffects(character);
        }
예제 #4
0
 private static void ServerSpawnIfReady(ICharacter character)
 {
     if (SharedIsCharacterCreated(character))
     {
         CharacterRespawnSystem.ServerOnCharacterCreated(character);
     }
 }
예제 #5
0
        private void ServerTimerTickCallback()
        {
            var time = Server.Game.FrameTime;

            serverRequests.ProcessAndRemoveByPair(
                pair =>
            {
                // process unstuck
                var character = pair.Key;
                var request   = pair.Value;

                if (character.GetPublicState <ICharacterPublicState>()
                    .IsDead)
                {
                    // character is dead
                    this.CallClient(character, _ => _.ClientRemote_UnstuckFailedDead());
                    return(true);    // remove this request
                }

                if (request.InitialPosition.DistanceSquaredTo(character.Position)
                    > MaxUnstuckMovementDistance * MaxUnstuckMovementDistance)
                {
                    // character moved
                    ServerNotifyUnstuckCancelledCharacterMoved(character);
                    return(true);    // remove this request
                }

                if (!SharedValidateCanUnstuck(character))
                {
                    return(true);    // remove this request
                }

                if (request.UnstuckAfter > time)
                {
                    // time is not expired yet
                    return(false);    // don't remove this request
                }

                // try to teleport player away but nearby
                if (!CharacterRespawnSystem.ServerTryPlaceCharacterNearby(character, character.Position))
                {
                    // try to simply respawn in starting area (only the character position will be changed)
                    ServerPlayerSpawnManager.PlacePlayer(character, isRespawn: false);
                }

                Logger.Info(
                    $"Character unstuck from {request.InitialPosition} to {character.TilePosition}",
                    character);
                this.CallClient(character, _ => _.ClientRemote_UnstuckSuccessful());
                return(true);    // remove this request
            },
                removeCallback: pair =>
            {
                var character = pair.Key;
                ServerOnUnstuckRequestRemoved(character);
            });
        }
예제 #6
0
        /// <summary>
        /// Please do not invoke for the already spawned character.
        /// </summary>
        public static void ServerSpawnIfReady(ICharacter character)
        {
            if (!SharedIsCharacterCreated(character))
            {
                return;
            }

            Api.SafeInvoke(() => ServerCharacterCreated?.Invoke(character));
            CharacterRespawnSystem.ServerOnCharacterCreated(character);
        }
예제 #7
0
        public static void OnCharacterInitialize(ICharacter character)
        {
            if (character.IsNpc)
            {
                return;
            }

            if (PlayerCharacter.GetPublicState(character).IsDead)
            {
                CharacterDespawnSystem.ServerTeleportPlayerCharacterToServiceArea(character);
                CharacterRespawnSystem.ServerRemoveStatusEffectsOnRespawn(character);
            }
            else if (PlayerCharacter.GetPrivateState(character).IsDespawned)
            {
                CharacterDespawnSystem.ServerTeleportPlayerCharacterToServiceArea(character);
            }
        }