public static void ServerExplode( [CanBeNull] ICharacter character, [CanBeNull] IProtoObjectExplosive protoObjectExplosive, ExplosionPreset explosionPreset, Vector2D epicenterPosition, DamageDescription damageDescriptionCharacters, IPhysicsSpace physicsSpace, ExecuteExplosionDelegate executeExplosionCallback) { ValidateIsServer(); // schedule explosion charred ground spawning ServerTimersSystem.AddAction( // the delay is quite small and just needed to ensure // that the charred ground spawned some time after this object is destroyed delaySeconds: explosionPreset.SpriteAnimationDuration * 0.5, () => { var tilePosition = (Vector2Ushort)epicenterPosition; if (!Server.World.GetTile(tilePosition) .StaticObjects .Any(so => so.ProtoStaticWorldObject is ObjectCharredGround)) { // spawn charred ground var objectCharredGround = Server.World.CreateStaticWorldObject <ObjectCharredGround>(tilePosition); var objectCharredGroundOffset = epicenterPosition - tilePosition.ToVector2D(); if (objectCharredGroundOffset != Vector2D.Zero) { ObjectCharredGround.ServerSetWorldOffset(objectCharredGround, objectCharredGroundOffset.ToVector2F()); } } }); // schedule explosion damage ServerTimersSystem.AddAction( delaySeconds: explosionPreset.ServerDamageApplyDelay, () => { // prepare weapon caches var characterFinalStatsCache = character != null ? character.SharedGetFinalStatsCache() : FinalStatsCache.Empty; var weaponFinalCache = new WeaponFinalCache(character, characterFinalStatsCache, weapon: null, protoWeapon: null, protoObjectExplosive: protoObjectExplosive, damageDescription: damageDescriptionCharacters); // execute explosion executeExplosionCallback( positionEpicenter: epicenterPosition, physicsSpace: physicsSpace, weaponFinalCache: weaponFinalCache); }); }
private static double ServerCalculateTotalDamageByExplosive( IProtoObjectExplosive protoObjectExplosive, IProtoStaticWorldObject targetStaticWorldObjectProto, double damagePreMultiplier) { var damage = protoObjectExplosive.ServerCalculateTotalDamageByExplosive(targetStaticWorldObjectProto); damage *= damagePreMultiplier; return(damage); }
private void ClientRemote_NoDamageToDepositUnderClaimDelay(IProtoGameObject protoObjectExplosive) { var icon = protoObjectExplosive switch { IProtoObjectExplosive objectExplosive => objectExplosive.Icon, IProtoItem item => item.Icon, _ => null }; NotificationSystem.ClientShowNotification( string.Format(NotificationNoDamageToDepositUnderCooldown_TitleFormat, this.Name), NotificationNoDamageToDepositUnderCooldown_Description, color: NotificationColor.Bad, icon); } }
public static void ServerExplode( [CanBeNull] ICharacter character, [CanBeNull] IProtoObjectExplosive protoObjectExplosive, ExplosionPreset explosionPreset, Vector2D epicenterPosition, DamageDescription damageDescriptionCharacters, IPhysicsSpace physicsSpace, ExecuteExplosionDelegate executeExplosionCallback) { ValidateIsServer(); // schedule explosion charred ground spawning ServerTimersSystem.AddAction( delaySeconds: explosionPreset.SpriteAnimationDuration * 0.5, () => { var tilePosition = (Vector2Ushort)epicenterPosition; // remove existing charred ground objects at the same tile foreach (var staticWorldObject in Shared.WrapInTempList( Server.World.GetTile(tilePosition).StaticObjects)) { if (staticWorldObject.ProtoStaticWorldObject is ObjectCharredGround) { Server.World.DestroyObject(staticWorldObject); } } // spawn charred ground var objectCharredGround = Server.World .CreateStaticWorldObject <ObjectCharredGround>(tilePosition); var objectCharredGroundOffset = epicenterPosition - tilePosition.ToVector2D(); if (objectCharredGroundOffset != Vector2D.Zero) { ObjectCharredGround.ServerSetWorldOffset(objectCharredGround, (Vector2F)objectCharredGroundOffset); } }); // schedule explosion damage ServerTimersSystem.AddAction( delaySeconds: explosionPreset.ServerDamageApplyDelay, () => { // prepare weapon caches var characterFinalStatsCache = character?.SharedGetFinalStatsCache() ?? FinalStatsCache.Empty; var weaponFinalCache = new WeaponFinalCache(character, characterFinalStatsCache, weapon: null, protoWeapon: null, protoObjectExplosive: protoObjectExplosive, damageDescription: damageDescriptionCharacters); // execute explosion executeExplosionCallback( positionEpicenter: epicenterPosition, physicsSpace: physicsSpace, weaponFinalCache: weaponFinalCache); }); }
protected abstract void PrepareProtoItemExplosive( out IProtoObjectExplosive objectExplosiveProto);
public WeaponFinalCache( ICharacter character, FinalStatsCache characterFinalStatsCache, [CanBeNull] IItem weapon, [CanBeNull] IProtoItemWeapon protoWeapon, DamageDescription damageDescription, IProtoObjectExplosive protoObjectExplosive = null) { this.Character = character; this.Weapon = weapon; this.ProtoWeapon = (IProtoItemWeapon)weapon?.ProtoItem ?? protoWeapon; this.ProtoObjectExplosive = protoObjectExplosive; if (damageDescription == null) { // TODO: it looks like not implemented yet and we should throw an exception here // fallback in case weapon don't provide damage description (such as no-ammo weapon) damageDescription = new DamageDescription( damageValue: 0, armorPiercingCoef: 0, finalDamageMultiplier: 1, rangeMax: 0, damageDistribution: new DamageDistribution()); } var descriptionDamages = damageDescription.DamageProportions; var damageDistributionsCount = descriptionDamages.Count; var resultDamageDistributions = new List <DamageProportion>(damageDistributionsCount); var totalPercents = 0d; for (var index = 0; index < damageDistributionsCount; index++) { var source = descriptionDamages[index]; var statName = this.GetProportionStatName(source.DamageType); var resultDamageProportion = source.Proportion + characterFinalStatsCache[statName]; if (resultDamageProportion <= 0) { continue; } resultDamageDistributions.Add(new DamageProportion(source.DamageType, resultDamageProportion)); totalPercents += resultDamageProportion; } if (damageDistributionsCount > 0 && Math.Abs(totalPercents - 1) > 0.001d) { throw new Exception( "Sum of all damage proportions must be exactly 1. Calculated value: " + totalPercents.ToString("F3")); } this.DamageDistributions = resultDamageDistributions; this.DamageValue = damageDescription.DamageValue * (protoWeapon?.DamageMultiplier ?? 1.0) + characterFinalStatsCache[StatName.DamageAdd]; if (protoWeapon?.WeaponSkillProto != null) { var statName = protoWeapon.WeaponSkillProto.StatNameDamageBonusMultiplier; this.DamageValue *= characterFinalStatsCache.GetMultiplier(statName); } this.RangeMax = damageDescription.RangeMax * (protoWeapon?.RangeMultipier ?? 1.0) + characterFinalStatsCache[StatName.AttackRangeMax]; var armorPiercingCoef = (1 + characterFinalStatsCache[StatName.AttackArmorPiercingMultiplier]) * (damageDescription.ArmorPiercingCoef * (protoWeapon?.ArmorPiercingMultiplier ?? 1.0) + characterFinalStatsCache[StatName.AttackArmorPiercingValue]); this.InvertedArmorPiercingCoef = 1 - armorPiercingCoef; this.FinalDamageMultiplier = damageDescription.FinalDamageMultiplier + characterFinalStatsCache[StatName.AttackFinalDamageMultiplier]; }
0; // no heavy weapon experience, since it is not even a weapon protected override void PrepareProtoItemExplosive( out IProtoObjectExplosive objectExplosiveProto) { objectExplosiveProto = GetProtoEntity <ObjectBombMining>(); }