public static void ServerDespawnDrone(IDynamicWorldObject objectDrone, bool isReturnedToPlayer)
        {
            var privateState = objectDrone.GetPrivateState <DronePrivateState>();
            var publicState  = objectDrone.GetPublicState <DronePublicState>();

            publicState.ResetTargetPosition();

            if (privateState.IsDespawned)
            {
                return;
            }

            var droneItem      = privateState.AssociatedItem;
            var protoItemDrone = (IProtoItemDrone)droneItem.ProtoItem;
            var characterOwner = privateState.CharacterOwner;
            var world          = Server.World;

            var protoDrone = protoItemDrone.ProtoDrone;

            protoDrone.ServerOnDroneDroppedOrReturned(objectDrone, characterOwner, isReturnedToPlayer);

            // recreate physics (as despawned drone doesn't have any physics)
            privateState.IsDespawned = true;
            world.StopPhysicsBody(objectDrone.PhysicsBody);
            objectDrone.ProtoWorldObject.SharedCreatePhysics(objectDrone);
            world.SetPosition(objectDrone,
                              ServerCharacterDeathMechanic.ServerGetGraveyardPosition().ToVector2D());

            privateState.CharacterOwner = null;
            ServerOnDroneControlRemoved(characterOwner, objectDrone);

            var currentDurability = (int)(objectDrone.GetPublicState <DronePublicState>().StructurePointsCurrent
                                          / protoItemDrone.DurabilityToStructurePointsConversionCoefficient);

            if (currentDurability <= 1)
            {
                currentDurability = 0;
            }

            var deltaDurabilility = (int)(ItemDurabilitySystem.SharedGetDurabilityValue(droneItem)
                                          - currentDurability);

            if (deltaDurabilility <= 0)
            {
                return;
            }

            ItemDurabilitySystem.ServerModifyDurability(droneItem,
                                                        -deltaDurabilility);

            if (droneItem.IsDestroyed)
            {
                // drone item degraded to 100%, notify the player
                ItemDurabilitySystem.Instance.CallClient(characterOwner,
                                                         _ => _.ClientRemote_ItemBroke(droneItem.ProtoItem));
            }
        }
Exemple #2
0
        protected override bool ServerIsCompleted(ICharacter character, PlayerTaskState state)
        {
            if (!character.ServerIsOnline ||
                character.TilePosition == ServerCharacterDeathMechanic.ServerGetGraveyardPosition())
            {
                return(false);
            }

            return(character.Tile.ProtoTile == this.ProtoTile);
        }
        private static void ServerUpdate()
        {
            var serverTime = Server.Game.FrameTime;

            foreach (var character in Server.Characters.EnumerateAllPlayerCharacters(onlyOnline: false))
            {
                if (ServerIsNeedDespawn(character, serverTime))
                {
                    ServerCharacterDeathMechanic.DespawnCharacter(character);
                }
            }
        }
        public static void ServerPutIntoGarage(IDynamicWorldObject vehicle)
        {
            var position = ServerCharacterDeathMechanic.ServerGetGraveyardPosition().ToVector2D();

            var vehiclePrivateState = vehicle.GetPrivateState <VehiclePrivateState>();

            if (vehiclePrivateState.IsInGarage &&
                vehicle.Position == position)
            {
                // already in garage
                return;
            }

            var vehicleCurrentPilot = vehicle.GetPublicState <VehiclePublicState>().PilotCharacter;

            if (vehicleCurrentPilot != null)
            {
                VehicleSystem.ServerCharacterExitCurrentVehicle(vehicleCurrentPilot, force: true);
            }

            vehiclePrivateState.IsInGarage = true;

            Server.World.SetPosition(vehicle,
                                     position,
                                     writeToLog: false);

            VehicleSystem.ServerResetLastVehicleMapMark(vehiclePrivateState);

            vehicle.ProtoWorldObject.SharedCreatePhysics(vehicle);
            Logger.Important("Vehicle put into the garage: " + vehicle,
                             characterRelated: ServerRemoteContext.IsRemoteCall
                                                   ? ServerRemoteContext.Character
                                                   : null);

            if (ServerRemoteContext.IsRemoteCall)
            {
                // this action is done by player
                return;
            }

            // server put vehicle into garage - notify owners
            foreach (var owner in vehiclePrivateState.Owners)
            {
                var player = Server.Characters.GetPlayerCharacter(owner);
                if (player == null)
                {
                    continue;
                }

                var protoVehicle = (IProtoVehicle)vehicle.ProtoGameObject;
                Instance.CallClient(player, _ => _.ClientRemote_VehicleInGarage(protoVehicle));
            }
        }
        public void ServerReduceHealth(double damage, IGameObjectWithProto damageSource)
        {
            if (damage <= 0)
            {
                return;
            }

            if (this.HealthCurrent <= 0)
            {
                return;
            }

            if (damageSource != null)
            {
                // it's important to register the damage source before the damage is applied
                // (to use it in case of the subsequent death)
                CharacterDamageTrackingSystem.ServerRegisterDamage(damage,
                                                                   (ICharacter)this.GameObject,
                                                                   new ServerDamageSourceEntry(damageSource));
            }

            var newHealth = this.HealthCurrent - damage;

            if (newHealth <= 0 &&
                ((ICharacter)this.GameObject).IsNpc &&
                damageSource?.ProtoGameObject is IProtoStatusEffect)
            {
                var attackerCharacter = GetAttackerCharacter(damageSource, out _);
                if (attackerCharacter is null ||
                    attackerCharacter.IsNpc)
                {
                    // Don't allow killing mob by a status effect which is NOT added by a player character.
                    // This is a workaround to kill quests which cannot be finished
                    // when creature is killed by a status effect.
                    // TODO: Should be removed when we enable the damage tracking for mobs damage.
                    newHealth = float.Epsilon;
                }
            }

            this.ServerSetHealthCurrent((float)newHealth);

            if (newHealth <= 0)
            {
                var attackerCharacter = GetAttackerCharacter(damageSource, out var weaponSkill);
                ServerCharacterDeathMechanic.OnCharacterKilled(
                    attackerCharacter,
                    targetCharacter: (ICharacter)this.GameObject,
                    weaponSkill);
            }
        }
Exemple #6
0
        public void ServerReduceHealth(double damage, IGameObjectWithProto damageSource)
        {
            if (damage <= 0)
            {
                return;
            }

            if (this.HealthCurrent <= 0)
            {
                return;
            }

            var damagedCharacter = (ICharacter)this.GameObject;

            if (damageSource is not null)
            {
                // it's important to register the damage source before the damage is applied
                // (to use it in case of the subsequent death)
                CharacterDamageTrackingSystem.ServerRegisterDamage(damage,
                                                                   damagedCharacter,
                                                                   new ServerDamageSourceEntry(damageSource));
            }

            var newHealth = this.HealthCurrent - damage;

            if (newHealth <= 0 &&
                damagedCharacter.IsNpc &&
                damageSource?.ProtoGameObject is IProtoStatusEffect)
            {
                var attackerCharacter = GetAttackerCharacter(damageSource, out _);
                if (attackerCharacter is null ||
                    attackerCharacter.IsNpc)
                {
                    // don't allow killing a mob by a status effect which is NOT added by a player character
                    newHealth = float.Epsilon;
                }
            }

            this.ServerSetHealthCurrent((float)newHealth);

            if (newHealth <= 0)
            {
                var attackerCharacter = GetAttackerCharacter(damageSource, out var weaponSkill);
                ServerCharacterDeathMechanic.OnCharacterKilled(
                    attackerCharacter,
                    targetCharacter: damagedCharacter,
                    weaponSkill);
            }
        }
        public static void SpawnPlayer(ICharacter character, bool isRespawn)
        {
            ServerAddTorchItemIfNoItems(character);

            if (character.IsInitialized &&
                CharacterCreationSystem.SharedIsCharacterCreated(character))
            {
                PlacePlayer(character, isRespawn);
            }
            else
            {
                // first time spawn, requires character creation
                ServerCharacterDeathMechanic.DespawnCharacter(character);
            }
        }
        /// <summary>
        /// Set health - it will be clamped automatically.
        /// </summary>
        public void ServerSetHealthCurrent(float health, bool overrideDeath = false)
        {
            this.SharedTryRefreshFinalCache();

            var character            = (ICharacter)this.GameObject;
            var characterPublicState = character.GetPublicState <ICharacterPublicState>();

            if (characterPublicState.IsDead &&
                !overrideDeath)
            {
                // cannot change health this way for the dead character
                return;
            }

            health = MathHelper.Clamp(health, min: 0, max: this.HealthMax);
            if (this.HealthCurrent == health &&
                !overrideDeath)
            {
                return;
            }

            if (health < this.HealthCurrent)
            {
                if (!character.IsNpc &&
                    CharacterInvincibilitySystem.ServerIsInvincible(character))
                {
                    // don't apply damage - character is invincible
                    //Api.Logger.Important(
                    //    $"Cannot reduce character health - {character}: character is in invincible mode");
                    health = MathHelper.Clamp(this.HealthCurrent, min: 0, max: this.HealthMax);
                }
            }

            this.HealthCurrent = health;

            if (health <= 0)
            {
                characterPublicState.IsDead = true;
                Api.Logger.Important("Character dead: " + character);
                ServerCharacterDeathMechanic.OnCharacterDeath(character);
            }
            else if (characterPublicState.IsDead)
            {
                characterPublicState.IsDead = false;
                Api.Logger.Important("Character is not dead anymore: " + character);
            }
        }
Exemple #9
0
        protected override void ServerInitialize(ServerInitializeData data)
        {
            base.ServerInitialize(data);
            if (!data.IsFirstTimeInit)
            {
                return;
            }

            var item        = data.GameObject;
            var protoDrone  = LazyProtoDrone.Value;
            var objectDrone = Server.World.CreateDynamicWorldObject(
                protoDrone,
                ServerCharacterDeathMechanic.ServerGetGraveyardPosition().ToVector2D());

            protoDrone.ServerSetupAssociatedItem(objectDrone, item);
            data.PrivateState.WorldObjectDrone = objectDrone;
        }
Exemple #10
0
            public override void ServerInitialize(IServerConfiguration serverConfiguration)
            {
                base.ServerInitialize(serverConfiguration);

                CharacterStyleSystem.ServerCharacterAppearanceSelected
                    += ServerCharacterAppearanceSelectedHandler;

                foreach (var character in Server.Characters.EnumerateAllPlayerCharacters(onlyOnline: false))
                {
                    var privateState = PlayerCharacter.GetPrivateState(character);
                    if (!privateState.IsDespawned &&
                        !SharedIsCharacterCreated(character))
                    {
                        // despawn all invalid characters
                        ServerCharacterDeathMechanic.DespawnCharacter(character);
                    }
                }
            }
Exemple #11
0
        protected sealed override void ServerInitialize(ServerInitializeData data)
        {
            base.ServerInitialize(data);
            var publicState  = data.PublicState;
            var privateState = data.PrivateState;

            privateState.EnsureEverythingCreated();
            publicState.ServerEnsureEverythingCreated();

            publicState.IsDead = publicState.CurrentStats.HealthCurrent <= 0;
            ServerCharacterDeathMechanic.OnCharacterInitialize(data.GameObject);

            this.ServerPrepareCharacter(data);

            if (data.IsFirstTimeInit)
            {
                this.ServerInitializeCharacterFirstTime(data);
            }

            this.ServerInitializeCharacter(data);
        }
Exemple #12
0
        public static bool SharedOnDamageToCharacter(
            ICharacter targetCharacter,
            WeaponFinalCache weaponCache,
            double damageMultiplier,
            out double damageApplied)
        {
            var targetPublicState  = targetCharacter.GetPublicState <ICharacterPublicState>();
            var targetCurrentStats = targetPublicState.CurrentStats;

            if (targetCurrentStats.HealthCurrent <= 0)
            {
                // target character is dead, cannot apply damage to it
                damageApplied = 0;
                return(false);
            }

            if (Api.IsClient)
            {
                // we don't simulate the damage on the client side
                damageApplied = 0;
                return(true);
            }

            var attackerCharacter = weaponCache.Character;

            // calculate and apply damage on server
            var targetFinalStatsCache =
                targetCharacter.GetPrivateState <BaseCharacterPrivateState>()
                .FinalStatsCache;

            var totalDamage = ServerCalculateTotalDamage(
                weaponCache,
                targetCharacter,
                targetFinalStatsCache,
                damageMultiplier,
                clampDefenseTo1: true);

            if (totalDamage <= 0)
            {
                // damage suppressed by armor
                damageApplied = 0;
                return(true);
            }

            // Clamp the max receivable damage to x5 from the max health.
            // This will help in case when the too much damage is dealt (mega-bomb!)
            // to ensure the equipment will not receive excessive damaged.
            totalDamage = Math.Min(totalDamage, 5 * targetCurrentStats.HealthMax);

            // apply damage
            targetCurrentStats.ServerSetHealthCurrent((float)(targetCurrentStats.HealthCurrent - totalDamage));
            Api.Logger.Info(
                $"Damage applied to {targetCharacter} by {attackerCharacter}:\n{totalDamage} dmg, current health {targetCurrentStats.HealthCurrent}/{targetCurrentStats.HealthMax}, {weaponCache.Weapon}");

            if (targetCurrentStats.HealthCurrent <= 0)
            {
                // killed!
                ServerCharacterDeathMechanic.OnCharacterKilled(
                    targetCharacter,
                    attackerCharacter,
                    weaponCache.Weapon,
                    weaponCache.ProtoWeapon);
            }

            damageApplied = totalDamage;
            ServerApplyDamageToEquippedItems(targetCharacter, damageApplied);

            return(true);
        }