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; }
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); }