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;
            }
Exemple #2
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);
        }