static float GetDamageToInflict(Actor target, ProjectileArgs args, WarheadInfo warhead, float modifier) { // don't hit air units with splash from ground explosions, etc if (!WeaponValidForTarget(args.weapon, target)) return 0f; var health = target.Info.Traits.GetOrDefault<HealthInfo>(); if( health == null ) return 0f; var distance = (int)Math.Max(0, (target.CenterLocation - args.dest).Length - health.Radius); var falloff = (float)GetDamageFalloff(distance / warhead.Spread); var rawDamage = (float)(warhead.Damage * modifier * falloff); var multiplier = (float)warhead.EffectivenessAgainst(target); return (float)(rawDamage * multiplier); }
public static void DoImpact(WarheadInfo warhead, ProjectileArgs args) { var world = args.firedBy.World; var targetTile = Util.CellContaining(args.dest); if (!world.Map.IsInMap(targetTile)) return; var isWater = world.GetTerrainInfo(targetTile).IsWater; var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion; if (explosionType != null) world.AddFrameEndTask( w => w.Add(new Explosion(w, args.dest, explosionType, isWater, args.destAltitude))); Sound.Play(GetImpactSound(warhead, isWater), args.dest); if (warhead.SmudgeType != null) { var smudgeLayer = world.WorldActor.TraitsImplementing<SmudgeLayer>() .FirstOrDefault(x => x.Info.Type == warhead.SmudgeType); if (smudgeLayer == null) throw new NotImplementedException("Unknown smudge type `{0}`".F(warhead.SmudgeType)); if (warhead.Size[0] > 0) { var smudgeCells = world.FindTilesInCircle(targetTile, warhead.Size[0]); if (warhead.Size.Length == 2 ) smudgeCells = smudgeCells.Except(world.FindTilesInCircle(targetTile, warhead.Size[1])) ; foreach (var sc in smudgeCells) { smudgeLayer.AddSmudge(sc); if (warhead.Ore) world.WorldActor.Trait<ResourceLayer>().Destroy(sc); } } else smudgeLayer.AddSmudge(targetTile); } if (warhead.Ore) world.WorldActor.Trait<ResourceLayer>().Destroy(targetTile); switch (warhead.DamageModel) { case DamageModel.Normal: { var maxSpread = warhead.Spread * (float)Math.Log(Math.Abs(warhead.Damage), 2); var hitActors = world.FindUnitsInCircle(args.dest, maxSpread); foreach (var victim in hitActors) { var damage = (int)GetDamageToInflict(victim, args, warhead, args.firepowerModifier); victim.InflictDamage(args.firedBy, damage, warhead); } } break; case DamageModel.PerCell: { foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0])) foreach (var unit in world.FindUnits(Game.CellSize * t, Game.CellSize * (t + new float2(1,1)))) unit.InflictDamage(args.firedBy, (int)(warhead.Damage * warhead.EffectivenessAgainst(unit)), warhead); } break; } }
public static void DoImpact(WarheadInfo warhead, ProjectileArgs args) { var world = args.firedBy.World; var targetTile = args.dest.ToCPos(); if (!world.Map.IsInMap(targetTile)) return; var isWater = args.destAltitude == 0 && world.GetTerrainInfo(targetTile).IsWater; var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion; if (explosionType != null) world.AddFrameEndTask( w => w.Add(new Explosion(w, args.dest, explosionType, isWater, args.destAltitude))); Sound.Play(GetImpactSound(warhead, isWater), args.dest); var smudgeLayers = world.WorldActor.TraitsImplementing<SmudgeLayer>().ToDictionary(x => x.Info.Type); if (warhead.Size[0] > 0) { var resLayer = world.WorldActor.Trait<ResourceLayer>(); var allCells = world.FindTilesInCircle(targetTile, warhead.Size[0]).ToList(); // `smudgeCells` might want to just be an outer shell of the cells: IEnumerable<CPos> smudgeCells = allCells; if (warhead.Size.Length == 2) smudgeCells = smudgeCells.Except(world.FindTilesInCircle(targetTile, warhead.Size[1])); // Draw the smudges: foreach (var sc in smudgeCells) { var smudgeType = world.GetTerrainInfo(sc).AcceptsSmudgeType.FirstOrDefault(t => warhead.SmudgeType.Contains(t)); if (smudgeType == null) continue; SmudgeLayer smudgeLayer; if (!smudgeLayers.TryGetValue(smudgeType, out smudgeLayer)) throw new NotImplementedException("Unknown smudge type `{0}`".F(smudgeType)); smudgeLayer.AddSmudge(sc); if (warhead.Ore) resLayer.Destroy(sc); } // Destroy all resources in range, not just the outer shell: foreach (var cell in allCells) { if (warhead.Ore) resLayer.Destroy(cell); } } else { var smudgeType = world.GetTerrainInfo(targetTile).AcceptsSmudgeType.FirstOrDefault(t => warhead.SmudgeType.Contains(t)); if (smudgeType != null) { SmudgeLayer smudgeLayer; if (!smudgeLayers.TryGetValue(smudgeType, out smudgeLayer)) throw new NotImplementedException("Unknown smudge type `{0}`".F(smudgeType)); smudgeLayer.AddSmudge(targetTile); } } if (warhead.Ore) world.WorldActor.Trait<ResourceLayer>().Destroy(targetTile); switch (warhead.DamageModel) { case DamageModel.Normal: { var maxSpread = warhead.Spread * (float)Math.Log(Math.Abs(warhead.Damage), 2); var hitActors = world.FindUnitsInCircle(args.dest, (int)maxSpread); foreach (var victim in hitActors) { var damage = (int)GetDamageToInflict(victim, args, warhead, args.firepowerModifier); victim.InflictDamage(args.firedBy, damage, warhead); } } break; case DamageModel.PerCell: { foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0])) foreach (var unit in world.FindUnits(t.ToPPos(), (t + new CVec(1,1)).ToPPos())) unit.InflictDamage(args.firedBy, (int)(warhead.Damage * warhead.EffectivenessAgainst(unit)), warhead); } break; } }
public static void DoImpact(WarheadInfo warhead, ProjectileArgs args, int2 visualLocation) { var world = args.firedBy.World; var targetTile = ((1f / Game.CellSize) * args.dest.ToFloat2()).ToInt2(); var isWater = world.GetTerrainType(targetTile) == TerrainType.Water; if (warhead.Explosion != 0) world.AddFrameEndTask( w => w.Add(new Explosion(w, visualLocation, warhead.Explosion, isWater))); Sound.Play(GetImpactSound(warhead, isWater)); if (!isWater) world.Map.AddSmudge(targetTile, warhead); if (warhead.Ore) world.WorldActor.traits.Get<ResourceLayer>().Destroy(targetTile); var firepowerModifier = args.firedBy.traits .WithInterface<IFirepowerModifier>() .Select(a => a.GetFirepowerModifier()) .Product(); switch (warhead.DamageModel) { case DamageModel.Normal: { var maxSpread = warhead.Spread * (float)Math.Log(Math.Abs(warhead.Damage), 2); var hitActors = world.FindUnitsInCircle(args.dest, maxSpread); foreach (var victim in hitActors) victim.InflictDamage(args.firedBy, (int)GetDamageToInflict(victim, args, warhead, firepowerModifier), warhead); } break; case DamageModel.PerCell: { foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0])) foreach (var unit in world.FindUnits(Game.CellSize * t, Game.CellSize * (t + new float2(1,1)))) unit.InflictDamage(args.firedBy, (int)(warhead.Damage * warhead.EffectivenessAgainst( unit.Info.Traits.Get<OwnedActorInfo>().Armor)), warhead); } break; } }
static float GetDamageToInflict(Actor target, ProjectileArgs args, WarheadInfo warhead, float modifier) { var selectable = target.Info.Traits.GetOrDefault<SelectableInfo>(); var radius = selectable != null ? selectable.Radius : 0; var distance = Math.Max(0, (target.CenterLocation - args.dest).Length - radius); var rawDamage = warhead.Damage * modifier * (float)Math.Exp(-distance / warhead.Spread); var multiplier = warhead.EffectivenessAgainst(target.Info.Traits.Get<OwnedActorInfo>().Armor); return rawDamage * multiplier; }
static float GetDamageToInflict(WPos pos, Actor target, WarheadInfo warhead, WeaponInfo weapon, float modifier, bool withFalloff) { // don't hit air units with splash from ground explosions, etc if (!weapon.IsValidAgainst(target)) return 0; var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>(); if (healthInfo == null) return 0; var rawDamage = (float)warhead.Damage; if (withFalloff) { var distance = Math.Max(0, (target.CenterPosition - pos).Length - healthInfo.Radius.Range); var falloff = (float)GetDamageFalloff(distance * 1f / warhead.Spread.Range); rawDamage = (float)(falloff * rawDamage); } return (float)(rawDamage * modifier * (float)warhead.EffectivenessAgainst(target.Info)); }
static float GetDamageToInflict(WPos pos, Actor target, WarheadInfo warhead, WeaponInfo weapon, float modifier) { // don't hit air units with splash from ground explosions, etc if (!weapon.IsValidAgainst(target)) return 0f; var health = target.Info.Traits.GetOrDefault<HealthInfo>(); if( health == null ) return 0f; var distance = (int)Math.Max(0, (target.CenterPosition - pos).Length * Game.CellSize / 1024 - health.Radius); var falloff = (float)GetDamageFalloff(distance / warhead.Spread); var rawDamage = (float)(warhead.Damage * modifier * falloff); var multiplier = (float)warhead.EffectivenessAgainst(target.Info); return (float)(rawDamage * multiplier); }