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