Exemplo n.º 1
0
        private void ServerExplode(IStaticWorldObject worldObject, ICharacter character)
        {
            try
            {
                Logger.Important(worldObject + " exploded");
                this.ServerSendObjectDestroyedEvent(worldObject);

                ExplosionHelper.ServerExplode(
                    character: character,
                    protoExplosive: this,
                    protoWeapon: null,
                    explosionPreset: this.ExplosionPreset,
                    epicenterPosition: worldObject.TilePosition.ToVector2D() + this.Layout.Center,
                    damageDescriptionCharacters: this.damageDescriptionCharacters,
                    physicsSpace: worldObject.PhysicsBody.PhysicsSpace,
                    executeExplosionCallback: this.ServerExecuteExplosion);

                if (this.IsActivatesRaidModeForLandClaim)
                {
                    var explosionRadius = (int)Math.Ceiling(this.DamageRadius);
                    var bounds          = new RectangleInt(x: worldObject.TilePosition.X - explosionRadius,
                                                           y: worldObject.TilePosition.Y - explosionRadius,
                                                           width: 2 * explosionRadius,
                                                           height: 2 * explosionRadius);

                    if (RaidingProtectionSystem.SharedCanRaid(bounds,
                                                              showClientNotification: false))
                    {
                        // try activate the raidblock
                        LandClaimSystem.ServerOnRaid(bounds, character);
                    }
                    else
                    {
                        // Raiding is not possible now due to raiding window
                        // Find if there is any land claim and in that case notify nearby players
                        // that the damage to objects there were not applied.
                        if (LandClaimSystem.SharedIsLandClaimedByAnyone(bounds))
                        {
                            using var tempPlayers = Api.Shared.GetTempList <ICharacter>();
                            Server.World.GetScopedByPlayers(worldObject, tempPlayers);
                            RaidingProtectionSystem.ServerNotifyShowNotificationRaidingNotAvailableNow(
                                tempPlayers.AsList());
                        }
                    }
                }
            }
            finally
            {
                Server.World.DestroyObject(worldObject);
            }
        }
Exemplo n.º 2
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;
            }
Exemplo n.º 3
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);
        }
Exemplo n.º 4
0
        private void ServerExplode(IItem item)
        {
            Server.Items.DestroyItem(item);

            // explode a primitive bomb in player position
            var character = item.Container.OwnerAsCharacter;

            if (character is null)
            {
                return;
            }

            var characterPublicState = character.GetPublicState <PlayerCharacterPublicState>();

            if (!characterPublicState.IsDead)
            {
                // ensure the wearer is killed by the explosion
                characterPublicState.CurrentStats.ServerSetHealthCurrent(0);
            }

            var targetPosition = character.Position;

            var protoBomb = ProtoObjectBomb;

            SharedExplosionHelper.ServerExplode(
                character: character,
                protoExplosive: protoBomb,
                protoWeapon: null,
                explosionPreset: protoBomb.ExplosionPreset,
                epicenterPosition: targetPosition,
                damageDescriptionCharacters: protoBomb.DamageDescriptionCharacters,
                physicsSpace: Server.World.GetPhysicsSpace(),
                executeExplosionCallback: protoBomb.ServerExecuteExplosion);

            // notify all characters about the explosion
            using var charactersObserving = Api.Shared.GetTempList <ICharacter>();
            const byte explosionEventRadius = 40;

            Server.World.GetCharactersInRadius(targetPosition.ToVector2Ushort(),
                                               charactersObserving,
                                               radius: explosionEventRadius,
                                               onlyPlayers: true);

            this.CallClient(charactersObserving.AsList(),
                            _ => _.ClientRemote_OnExplosion(targetPosition));

            // activate the raidblock if possible (the code is similar to ProtoObjectEplosive)
            var explosionRadius = (int)Math.Ceiling(protoBomb.DamageRadius);
            var bounds          = new RectangleInt(x: (int)Math.Round(character.Position.X - explosionRadius),
                                                   y: (int)Math.Round(character.Position.Y - explosionRadius),
                                                   width: 2 * explosionRadius,
                                                   height: 2 * explosionRadius);

            if (RaidingProtectionSystem.SharedCanRaid(bounds,
                                                      showClientNotification: false))
            {
                // try activate the raidblock
                LandClaimSystem.ServerOnRaid(bounds, character, isStructureDestroyed: false);
            }
            else
            {
                // Raiding is not possible now due to raiding window
                // Find if there is any land claim and in that case notify nearby players
                // that the damage to objects there was not applied.
                if (LandClaimSystem.SharedIsLandClaimedByAnyone(bounds))
                {
                    using var tempPlayers = Api.Shared.GetTempList <ICharacter>();
                    Server.World.GetScopedByPlayers(character, tempPlayers);
                    RaidingProtectionSystem.ServerNotifyShowNotificationRaidingNotAvailableNow(
                        tempPlayers.AsList());
                }
            }
        }
Exemplo n.º 5
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) ||
                 !PveSystem.SharedIsAllowStructureDamage(weaponCache.Character,
                                                         staticWorldObject,
                                                         showClientNotification: false)))
            {
                return(0);
            }

            if (weaponCache.ProtoObjectExplosive != null &&
                targetObject.ProtoWorldObject is IProtoStaticWorldObject targetStaticWorldObjectProto)
            {
                // special case - apply the explosive damage
                return(ServerCalculateTotalDamageByExplosive(weaponCache.ProtoObjectExplosive,
                                                             targetStaticWorldObjectProto,
                                                             damagePreMultiplier));
            }

            // these two cases apply only if damage dealt not by a bomb
            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 != null &&
                     !damagingCharacter.IsNpc)
            {
                // apply PvE damage multiplier
                totalDamage *= WeaponConstants.DamagePveMultiplier;
            }
            else if (damagingCharacter != null &&
                     damagingCharacter.IsNpc)
            {
                // apply creature damage multiplier
                totalDamage *= WeaponConstants.DamageCreaturesMultiplier;

                if (targetObject is ICharacter victim &&
                    !victim.ServerIsOnline &&
                    !victim.IsNpc)
                {
                    // don't deal creature damage to offline players
                    totalDamage = 0;
                }
            }

            if (isFriendlyFireCase)
            {
                totalDamage *= WeaponConstants.DamageFriendlyFireMultiplier;
            }

            return(totalDamage);
        }