public NukeLaunch(Player firedBy, string name, WeaponInfo weapon, string weaponPalette, string upSequence, string downSequence, WPos launchPos, WPos targetPos, WDist velocity, int delay, bool skipAscent, string flashType) { this.firedBy = firedBy; this.weapon = weapon; this.weaponPalette = weaponPalette; this.downSequence = downSequence; this.delay = delay; turn = delay / 2; this.flashType = flashType; var offset = new WVec(WDist.Zero, WDist.Zero, velocity * turn); ascendSource = launchPos; ascendTarget = launchPos + offset; descendSource = targetPos + offset; descendTarget = targetPos; anim = new Animation(firedBy.World, name); anim.PlayRepeating(upSequence); pos = launchPos; if (weapon.Report != null && weapon.Report.Any()) Game.Sound.Play(weapon.Report.Random(firedBy.World.SharedRandom), pos); if (skipAscent) ticks = turn; }
public IonCannon(Player firedBy, WeaponInfo weapon, World world, CPos location, string effect, string palette, int delay) { this.firedBy = firedBy; this.weapon = weapon; this.palette = palette; weaponDelay = delay; target = Target.FromCell(world, location); anim = new Animation(world, effect); anim.PlayThen("idle", () => Finish(world)); }
public SwallowActor(Actor self, Target target, WeaponInfo weapon) { this.target = target; this.weapon = weapon; sandworm = self.Trait<Sandworm>(); positionable = self.Trait<Mobile>(); swallow = self.Trait<AttackSwallow>(); manager = self.Trait<UpgradeManager>(); radarPings = self.World.WorldActor.TraitOrDefault<RadarPings>(); }
public IonCannon(Player firedBy, WeaponInfo weapon, World world, WPos launchPos, CPos location, string effect, string sequence, string palette, int delay) { this.firedBy = firedBy; this.weapon = weapon; this.palette = palette; weaponDelay = delay; target = Target.FromCell(world, location); anim = new Animation(world, effect); anim.PlayThen(sequence, () => Finish(world)); if (weapon.Report != null && weapon.Report.Any()) Game.Sound.Play(SoundType.World, weapon.Report.Random(firedBy.World.SharedRandom), launchPos); }
public SwallowActor(Actor self, Target target, WeaponInfo weapon) { this.target = target; this.weapon = weapon; sandworm = self.Trait<Sandworm>(); positionable = self.Trait<Mobile>(); swallow = self.Trait<AttackSwallow>(); withSpriteBody = self.Trait<WithSpriteBody>(); radarPings = self.World.WorldActor.TraitOrDefault<RadarPings>(); countdown = swallow.Info.AttackTime; withSpriteBody.DefaultAnimation.ReplaceAnim(sandworm.Info.BurrowedSequence); stance = AttackState.Burrowed; location = target.Actor.Location; }
public SwallowActor(Actor self, Target target, WeaponInfo weapon) { this.target = target; this.weapon = weapon; sandworm = self.Trait<Sandworm>(); positionable = self.Trait<Mobile>(); swallow = self.Trait<AttackSwallow>(); renderUnit = self.Trait<RenderUnit>(); radarPings = self.World.WorldActor.TraitOrDefault<RadarPings>(); countdown = swallow.Info.AttackTime; renderUnit.DefaultAnimation.ReplaceAnim("burrowed"); stance = AttackState.Burrowed; location = target.Actor.Location; }
public Turret Turret; // where this weapon is mounted -- possibly shared #endregion Fields #region Constructors public Weapon(string weaponName, Turret turret, int[] localOffset) { Info = Rules.Weapons[weaponName.ToLowerInvariant()]; Burst = Info.Burst; Turret = turret; var barrels = new List<Barrel>(); for (var i = 0; i < localOffset.Length / 3; i++) barrels.Add(new Barrel { Position = new int2(localOffset[3 * i], localOffset[3 * i + 1]), Facing = localOffset[3 * i + 2] }); // if no barrels specified, the default is "turret position; turret facing". if (barrels.Count == 0) barrels.Add(new Barrel { Position = int2.Zero, Facing = 0 }); Barrels = barrels.ToArray(); }
public Leap(Actor self, Actor target, WeaponInfo weapon, WRange speed, WAngle angle) { var targetMobile = target.TraitOrDefault<Mobile>(); if (targetMobile == null) throw new InvalidOperationException("Leap requires a target actor with the Mobile trait"); this.weapon = weapon; this.angle = angle; mobile = self.Trait<Mobile>(); mobile.SetLocation(mobile.fromCell, mobile.fromSubCell, targetMobile.fromCell, targetMobile.fromSubCell); mobile.IsMoving = true; from = self.CenterPosition; to = targetMobile.fromCell.CenterPosition + MobileInfo.SubCellOffsets[targetMobile.fromSubCell]; length = Math.Max((to - from).Length / speed.Range, 1); self.Trait<RenderInfantry>().Attacking(self, Target.FromActor(target)); if (weapon.Report != null && weapon.Report.Any()) Sound.Play(weapon.Report.Random(self.World.SharedRandom), self.CenterPosition); }
public Turret Turret; // where this weapon is mounted -- possibly shared #endregion Fields #region Constructors public Weapon(string weaponName, Turret turret, int[] localOffset, int recoil) { Info = Rules.Weapons[weaponName.ToLowerInvariant()]; Burst = Info.Burst; Turret = turret; Recoil = recoil; var barrels = new List<Barrel>(); for (var i = 0; i < localOffset.Length / 5; i++) barrels.Add(new Barrel { TurretSpaceOffset = new PVecInt(localOffset[5 * i], localOffset[5 * i + 1]), ScreenSpaceOffset = new PVecInt(localOffset[5 * i + 2], localOffset[5 * i + 3]), Facing = localOffset[5 * i + 4] }); // if no barrels specified, the default is "turret position; turret facing". if (barrels.Count == 0) barrels.Add(new Barrel { TurretSpaceOffset = PVecInt.Zero, ScreenSpaceOffset = PVecInt.Zero, Facing = 0 }); Barrels = barrels.ToArray(); }
public Leap(Actor self, Actor target, WeaponInfo weapon, WDist speed, WAngle angle) { var targetMobile = target.TraitOrDefault<Mobile>(); if (targetMobile == null) throw new InvalidOperationException("Leap requires a target actor with the Mobile trait"); this.weapon = weapon; this.angle = angle; mobile = self.Trait<Mobile>(); mobile.SetLocation(mobile.FromCell, mobile.FromSubCell, targetMobile.FromCell, targetMobile.FromSubCell); mobile.IsMoving = true; from = self.CenterPosition; to = self.World.Map.CenterOfSubCell(targetMobile.FromCell, targetMobile.FromSubCell); length = Math.Max((to - from).Length / speed.Length, 1); // HACK: why isn't this using the interface? self.Trait<WithInfantryBody>().Attacking(self, Target.FromActor(target)); if (weapon.Report != null && weapon.Report.Any()) Sound.Play(weapon.Report.Random(self.World.SharedRandom), self.CenterPosition); }
public static bool WeaponValidForTarget(WeaponInfo weapon, Target target) { // todo: fix this properly. if (!target.IsValid) return false; if (!target.IsActor) return weapon.ValidTargets.Contains("Ground") // hack! || (weapon.ValidTargets.Contains("Water") && Game.world.GetTerrainType(Util.CellContaining(target.CenterLocation)) == "Water"); // even bigger hack! var targetable = target.Actor.TraitOrDefault<ITargetable>(); if (targetable == null || !weapon.ValidTargets.Intersect(targetable.TargetTypes).Any()) return false; if (weapon.Warheads.All( w => w.EffectivenessAgainst(target.Actor) <= 0)) return false; return true; }
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); }
public void RulesetLoaded(Ruleset rules, ActorInfo ai) { ExplosionWeapon = string.IsNullOrEmpty(Explosion) ? null : rules.Weapons[Explosion.ToLowerInvariant()]; }
public static bool WeaponValidForTarget( WeaponInfo weapon, World world, int2 location ) { if( weapon.ValidTargets.Contains( "Ground" ) && world.GetTerrainType( location ) != "Water" ) return true; if( weapon.ValidTargets.Contains( "Water" ) && world.GetTerrainType( location ) == "Water" ) return true; return false; }
public static bool WeaponValidForTarget(WeaponInfo weapon, Actor target) { var targetable = target.TraitOrDefault<ITargetable>(); if (targetable == null || !weapon.ValidTargets.Intersect(targetable.TargetTypes).Any()) return false; if (weapon.Warheads.All( w => w.EffectivenessAgainst(target) <= 0)) return false; return true; }
public static void DoImpact(WPos pos, WarheadInfo warhead, WeaponInfo weapon, Actor firedBy, float firepowerModifier) { var world = firedBy.World; var targetTile = pos.ToCPos(); if (!world.Map.IsInMap(targetTile)) return; var isWater = pos.Z == 0 && world.GetTerrainInfo(targetTile).IsWater; var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion; if (explosionType != null) world.AddFrameEndTask(w => w.Add(new Explosion(w, pos, explosionType))); Sound.Play(GetImpactSound(warhead, isWater), pos); 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 range = new WRange((int)maxSpread * 1024 / Game.CellSize); var hitActors = world.FindActorsInCircle(pos, range); foreach (var victim in hitActors) { var damage = (int)GetDamageToInflict(pos, victim, warhead, weapon, firepowerModifier); victim.InflictDamage(firedBy, damage, warhead); } } break; case DamageModel.PerCell: { foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0])) foreach (var unit in world.FindActorsInBox(t, t)) unit.InflictDamage(firedBy, (int)(warhead.Damage * warhead.EffectivenessAgainst(unit.Info)), warhead); } break; } }
public static void DoImpacts(WPos pos, Actor firedBy, WeaponInfo weapon, float damageModifier) { foreach (var wh in weapon.Warheads) { var warhead = wh; Action a = () => DoImpact(pos, warhead, weapon, firedBy, damageModifier); if (warhead.Delay > 0) firedBy.World.AddFrameEndTask( w => w.Add(new DelayedAction(warhead.Delay, a))); else a(); } }
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)); }
public void RulesetLoaded(Ruleset rules, ActorInfo ai) { WeaponInfo = rules.Weapons[Weapon.ToLowerInvariant()]; }
public static void DoImpact(WPos pos, WarheadInfo warhead, WeaponInfo weapon, Actor firedBy, float firepowerModifier) { var world = firedBy.World; var targetTile = world.Map.CellContaining(pos); if (!world.Map.Contains(targetTile)) return; var isWater = pos.Z <= 0 && world.Map.GetTerrainInfo(targetTile).IsWater; var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion; var explosionTypePalette = isWater ? warhead.WaterExplosionPalette : warhead.ExplosionPalette; if (explosionType != null) world.AddFrameEndTask(w => w.Add(new Explosion(w, pos, explosionType, explosionTypePalette))); Sound.Play(GetImpactSound(warhead, isWater), pos); var smudgeLayers = world.WorldActor.TraitsImplementing<SmudgeLayer>().ToDictionary(x => x.Info.Type); var resLayer = warhead.DestroyResources || !string.IsNullOrEmpty(warhead.AddsResourceType) ? world.WorldActor.Trait<ResourceLayer>() : null; if (warhead.Size[0] > 0) { var allCells = world.Map.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.Map.FindTilesInCircle(targetTile, warhead.Size[1])); // Draw the smudges: foreach (var sc in smudgeCells) { var smudgeType = world.Map.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.DestroyResources) resLayer.Destroy(sc); } // Destroy all resources in range, not just the outer shell: if (warhead.DestroyResources) foreach (var cell in allCells) resLayer.Destroy(cell); // Splatter resources: if (!string.IsNullOrEmpty(warhead.AddsResourceType)) { var resourceType = world.WorldActor.TraitsImplementing<ResourceType>() .FirstOrDefault(t => t.Info.Name == warhead.AddsResourceType); if (resourceType == null) Log.Write("debug", "Warhead defines an invalid resource type '{0}'".F(warhead.AddsResourceType)); else { foreach (var cell in allCells) { if (!resLayer.CanSpawnResourceAt(resourceType, cell)) continue; var splash = world.SharedRandom.Next(1, resourceType.Info.MaxDensity - resLayer.GetResourceDensity(cell)); resLayer.AddResource(resourceType, cell, splash); } } } } else { var smudgeType = world.Map.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.DestroyResources) world.WorldActor.Trait<ResourceLayer>().Destroy(targetTile); switch (warhead.DamageModel) { case DamageModel.Normal: { var maxSpread = new WRange((int)(warhead.Spread.Range * (float)Math.Log(Math.Abs(warhead.Damage), 2))); var hitActors = world.FindActorsInCircle(pos, maxSpread); foreach (var victim in hitActors) { var damage = (int)GetDamageToInflict(pos, victim, warhead, weapon, firepowerModifier, true); victim.InflictDamage(firedBy, damage, warhead); } } break; case DamageModel.PerCell: { foreach (var t in world.Map.FindTilesInCircle(targetTile, warhead.Size[0])) { foreach (var unit in world.ActorMap.GetUnitsAt(t)) { var damage = (int)GetDamageToInflict(pos, unit, warhead, weapon, firepowerModifier, false); unit.InflictDamage(firedBy, damage, warhead); } } } break; case DamageModel.HealthPercentage: { var range = new WRange(warhead.Size[0] * 1024); var hitActors = world.FindActorsInCircle(pos, range); foreach (var victim in hitActors) { var damage = GetDamageToInflict(pos, victim, warhead, weapon, firepowerModifier, false); if (damage != 0) // will be 0 if the target doesn't have HealthInfo { var healthInfo = victim.Info.Traits.Get<HealthInfo>(); damage = (float)(damage / 100 * healthInfo.HP); } victim.InflictDamage(firedBy, (int)damage, warhead); } } break; } }
public static bool WeaponValidForTarget(WeaponInfo weapon, Actor target) { var ownedInfo = target.Info.Traits.GetOrDefault<OwnedActorInfo>(); if (!weapon.ValidTargets.Contains(ownedInfo.TargetType)) return false; if (weapon.Warheads.All( w => w.EffectivenessAgainst(ownedInfo.Armor) <= 0)) return false; if (weapon.Underwater && !ownedInfo.WaterBound) return false; return true; }