Esempio n. 1
0
        public virtual double ServerCalculateTotalDamageByExplosive(
            ICharacter byCharacter,
            IStaticWorldObject targetStaticWorldObject)
        {
            var structureExplosiveDefenseCoef =
                targetStaticWorldObject.ProtoStaticWorldObject.StructureExplosiveDefenseCoef;

            structureExplosiveDefenseCoef = MathHelper.Clamp(structureExplosiveDefenseCoef, 0, 1);

            var explosiveDefensePenetrationCoef = this.StructureDefensePenetrationCoef;

            explosiveDefensePenetrationCoef = MathHelper.Clamp(explosiveDefensePenetrationCoef, 0, 1);

            if (!PveSystem.SharedIsAllowStaticObjectDamage(byCharacter,
                                                           targetStaticWorldObject,
                                                           showClientNotification: false))
            {
                return(0);
            }

            var damage = this.StructureDamage
                         * (1 - structureExplosiveDefenseCoef * (1 - explosiveDefensePenetrationCoef));

            return(damage);
        }
        public static IStaticWorldObject SharedGetCompatibleTarget(
            ICharacter character,
            Vector2Ushort worldPosition,
            out bool hasIncompatibleTarget,
            out bool isPveActionForbidden)
        {
            isPveActionForbidden = false;
            var tile = IsServer
                           ? Server.World.GetTile(worldPosition)
                           : Client.World.GetTile(worldPosition);

            var targetObject = tile.StaticObjects.FirstOrDefault();

            if (targetObject is null)
            {
                hasIncompatibleTarget = false;
                return(null);
            }

            if (!PveSystem.SharedIsAllowStaticObjectDamage(character, targetObject, showClientNotification: false))
            {
                hasIncompatibleTarget = true;
                isPveActionForbidden  = true;
                return(null);
            }

            if (!SharedIsValidDroneTarget(targetObject))
            {
                hasIncompatibleTarget = true;
                return(null);
            }

            hasIncompatibleTarget = false;
            return(targetObject);
        }
Esempio n. 3
0
        protected override double SharedCalculateDamageByWeapon(
            WeaponFinalCache weaponCache,
            double damagePreMultiplier,
            IStaticWorldObject targetObject,
            out double obstacleBlockDamageCoef)
        {
            if (!PveSystem.SharedIsAllowStaticObjectDamage(weaponCache.Character,
                                                           targetObject,
                                                           showClientNotification: false))
            {
                obstacleBlockDamageCoef = 0;
                return(0);
            }

            if (weaponCache.ProtoWeapon is IProtoItemToolMining protoItemToolMining)
            {
                // mining mineral with a mining device
                // block next damage completely - only one mineral could be mined at once
                obstacleBlockDamageCoef = 1;

                // get damage multiplier ("mining speed")
                var damageMultiplier = weaponCache.CharacterFinalStatsCache.GetMultiplier(StatName.MiningSpeed);

                return(protoItemToolMining.ServerGetDamageToMineral(targetObject)
                       * damageMultiplier
                       * RateActionMiningSpeedMultiplier.SharedValue);
            }

            if (weaponCache.ProtoWeapon is ItemNoWeapon)
            {
                // no damage with hands
                obstacleBlockDamageCoef = 1;

                if (IsClient)
                {
                    NotificationSystem.ClientShowNotification(NotificationUsePickaxe,
                                                              icon: this.Icon);
                }

                return(0);
            }

            // not a mining tool - call default damage apply method
            return(base.SharedCalculateDamageByWeapon(weaponCache,
                                                      damagePreMultiplier,
                                                      targetObject,
                                                      out obstacleBlockDamageCoef));
        }
Esempio n. 4
0
        protected override double SharedCalculateDamageByWeapon(
            WeaponFinalCache weaponCache,
            double damagePreMultiplier,
            IStaticWorldObject targetObject,
            out double obstacleBlockDamageCoef)
        {
            // ReSharper disable once VariableHidesOuterVariable
            if (!PveSystem.SharedIsAllowStaticObjectDamage(weaponCache.Character,
                                                           targetObject,
                                                           showClientNotification: false))
            {
                obstacleBlockDamageCoef = 0;
                return(0);
            }

            if (weaponCache.ProtoWeapon is IProtoItemToolWoodcutting protoItemToolWoodCutting)
            {
                // get damage multiplier ("woodcutting speed")
                obstacleBlockDamageCoef = 1;
                var damageMultiplier = weaponCache.CharacterFinalStatsCache.GetMultiplier(
                    StatName.WoodcuttingSpeed);

                return(protoItemToolWoodCutting.ServerGetDamageToTree(targetObject)
                       * damageMultiplier
                       * ToolsConstants.ActionWoodcuttingSpeedMultiplier
                       * this.SharedGetDamageMultiplierByGrowthProgress(targetObject));
            }

            if (weaponCache.ProtoWeapon is ItemNoWeapon)
            {
                // no damage with hands
                obstacleBlockDamageCoef = 1;

                if (IsClient)
                {
                    NotificationSystem.ClientShowNotification(NotificationUseAxe,
                                                              icon: this.Icon);
                }

                return(0);
            }

            // not a wood-cutting tool - call default damage apply method
            return(base.SharedCalculateDamageByWeapon(weaponCache,
                                                      damagePreMultiplier,
                                                      targetObject,
                                                      out obstacleBlockDamageCoef));
        }
Esempio n. 5
0
        private bool ValidateTarget(IStaticWorldObject targetObject, out Vector2D targetPoint)
        {
            targetPoint = Vector2D.Zero;
            if (!PveSystem.SharedIsAllowStaticObjectDamage(CurrentCharacter,
                                                           targetObject,
                                                           showClientNotification: false))
            {
                return(false);
            }
            var shape = targetObject.PhysicsBody.Shapes.FirstOrDefault(s => s.CollisionGroup == CollisionGroups.HitboxMelee);

            if (shape == null)
            {
                Api.Logger.Error("Automaton: target object has no HitBoxMelee shape " + targetObject);
                return(false);
            }
            targetPoint = ShapeCenter(shape) + targetObject.PhysicsBody.Position;
            return(AdditionalValidation(targetObject) && CheckForObstacles(targetObject, targetPoint));
        }
Esempio n. 6
0
        public static double ServerCalculateTotalDamage(
            WeaponFinalCache weaponCache,
            IWorldObject targetObject,
            FinalStatsCache targetFinalStatsCache,
            double damagePreMultiplier,
            bool clampDefenseTo1)
        {
            if (targetObject is IStaticWorldObject staticWorldObject &&
                (!RaidingProtectionSystem.SharedCanRaid(staticWorldObject,
                                                        showClientNotification: false) ||
                 !LandClaimShieldProtectionSystem.SharedCanRaid(staticWorldObject,
                                                                showClientNotification: false) ||
                 !PveSystem.SharedIsAllowStaticObjectDamage(weaponCache.Character,
                                                            staticWorldObject,
                                                            showClientNotification: false) ||
                 !NewbieProtectionSystem.SharedIsAllowStructureDamage(weaponCache.Character,
                                                                      staticWorldObject,
                                                                      showClientNotification: false)))
            {
                return(0);
            }

            if (targetObject.ProtoGameObject is IProtoVehicle &&
                !PveSystem.SharedIsAllowVehicleDamage(weaponCache,
                                                      (IDynamicWorldObject)targetObject,
                                                      showClientNotification: false))
            {
                return(0);
            }

            if (weaponCache.ProtoExplosive is not null &&
                targetObject is IStaticWorldObject targetStaticWorldObject)
            {
                // special case - apply the explosive damage to static object
                return(ServerCalculateTotalDamageByExplosive(weaponCache.Character,
                                                             weaponCache.ProtoExplosive,
                                                             targetStaticWorldObject,
                                                             damagePreMultiplier));
            }

            if (ServerIsRestrictedPvPDamage(weaponCache,
                                            targetObject,
                                            out var isPvPcase,
                                            out var isFriendlyFireCase))
            {
                return(0);
            }

            var damageValue = damagePreMultiplier * weaponCache.DamageValue;
            var invertedArmorPiercingCoef = weaponCache.InvertedArmorPiercingCoef;

            var totalDamage = 0d;

            // calculate total damage by summing all the damage components
            foreach (var damageDistribution in weaponCache.DamageDistributions)
            {
                var defenseStatName = SharedGetDefenseStatName(damageDistribution.DamageType);
                var defenseFraction = targetFinalStatsCache[defenseStatName];
                defenseFraction = MathHelper.Clamp(defenseFraction, 0, clampDefenseTo1 ? 1 : double.MaxValue);

                totalDamage += ServerCalculateDamageComponent(
                    damageValue,
                    invertedArmorPiercingCoef,
                    damageDistribution,
                    defenseFraction);
            }

            // multiply on final multiplier (usually used for expanding projectiles)
            totalDamage *= weaponCache.FinalDamageMultiplier;

            var damagingCharacter = weaponCache.Character;

            if (isPvPcase)
            {
                // apply PvP damage multiplier
                totalDamage *= WeaponConstants.DamagePvpMultiplier;
            }
            else if (damagingCharacter is not null &&
                     !damagingCharacter.IsNpc &&
                     targetObject.ProtoGameObject
                     is IProtoCharacterMob protoCharacterMob &&
                     !protoCharacterMob.IsBoss)
            {
                // apply PvE damage multiplier
                totalDamage *= WeaponConstants.DamagePveMultiplier;
            }
Esempio n. 7
0
        public virtual bool SharedOnDamage(
            WeaponFinalCache weaponCache,
            IStaticWorldObject targetObject,
            double damagePreMultiplier,
            out double obstacleBlockDamageCoef,
            out double damageApplied)
        {
            var objectPublicState       = GetPublicState(targetObject);
            var previousStructurePoints = objectPublicState.StructurePointsCurrent;

            if (previousStructurePoints <= 0f)
            {
                // already destroyed static world object
                obstacleBlockDamageCoef = 0;
                damageApplied           = 0;
                return(false);
            }

            var serverDamage = this.SharedCalculateDamageByWeapon(
                weaponCache,
                damagePreMultiplier,
                targetObject,
                out obstacleBlockDamageCoef);

            if (serverDamage < 0)
            {
                Logger.Warning(
                    $"Server damage less than 0 and this is suspicious. {this} calculated damage: {serverDamage:0.###}");
                serverDamage = 0;
            }

            if (IsClient)
            {
                // simply call these methods to display a client notification only!
                // they are not used for anything else here
                // to calculate damage they're used in WeaponDamageSystem.ServerCalculateTotalDamage method.
                RaidingProtectionSystem.SharedCanRaid(targetObject,
                                                      showClientNotification: true);
                LandClaimShieldProtectionSystem.SharedCanRaid(targetObject,
                                                              showClientNotification: true);
                PveSystem.SharedIsAllowStaticObjectDamage(weaponCache.Character,
                                                          targetObject,
                                                          showClientNotification: true);
                NewbieProtectionSystem.SharedIsAllowStructureDamage(weaponCache.Character,
                                                                    targetObject,
                                                                    showClientNotification: true);

                damageApplied = 0;
                return(true);
            }

            if (serverDamage <= 0)
            {
                // no damage applied
                damageApplied = 0;
                return(true);
            }

            // apply damage
            damageApplied = serverDamage;
            var newStructurePoints = (float)(previousStructurePoints - serverDamage);

            if (newStructurePoints < 0)
            {
                newStructurePoints = 0;
            }

            Logger.Info(
                $"Damage applied to {targetObject} by {weaponCache.Character}:\n{serverDamage} dmg, current structure points {newStructurePoints}/{this.StructurePointsMax}, {weaponCache.Weapon}");

            objectPublicState.StructurePointsCurrent = newStructurePoints;

            try
            {
                this.ServerOnStaticObjectDamageApplied(
                    weaponCache,
                    targetObject,
                    previousStructurePoints,
                    newStructurePoints);
            }
            catch (Exception ex)
            {
                Logger.Exception(ex, $"Problem on processing {nameof(this.ServerOnStaticObjectDamageApplied)}()");
            }

            if (newStructurePoints <= 0f)
            {
                this.ServerOnStaticObjectZeroStructurePoints(weaponCache, weaponCache.Character, targetObject);
            }

            return(true);
        }