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 = (int)Math.Max(0, (target.CenterPosition - pos).Length * Game.CellSize / 1024 - healthInfo.Radius); var falloff = (float)GetDamageFalloff(distance / warhead.Spread); rawDamage = (float)(falloff * rawDamage); } return((float)(rawDamage * modifier * (float)warhead.EffectivenessAgainst(target.Info))); }
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 = 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) { var world = args.firedBy.World; var targetTile = Util.CellContaining(args.dest); 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); 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, (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(Game.CellSize * t, Game.CellSize * (t + new int2(1, 1)))) { unit.InflictDamage(args.firedBy, (int)(warhead.Damage * warhead.EffectivenessAgainst(unit)), warhead); } } } break; } }