From d9194d1aa3c3a813409fa94406fd413f29735d88 Mon Sep 17 00:00:00 2001 From: Zimmermann Gyula Date: Sun, 8 Jul 2018 13:35:39 +0200 Subject: [PATCH 1/5] Add FireClusterWarhead --- .../Warheads/FireClusterWarhead.cs | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 OpenRA.Mods.Common/Warheads/FireClusterWarhead.cs diff --git a/OpenRA.Mods.Common/Warheads/FireClusterWarhead.cs b/OpenRA.Mods.Common/Warheads/FireClusterWarhead.cs new file mode 100644 index 000000000000..98360e1ef0a0 --- /dev/null +++ b/OpenRA.Mods.Common/Warheads/FireClusterWarhead.cs @@ -0,0 +1,115 @@ +#region Copyright & License Information +/* + * Copyright 2007-2019 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.GameRules; +using OpenRA.Mods.Common.Traits; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Warheads +{ + public class FireClusterWarhead : Warhead, IRulesetLoaded + { + [WeaponReference, FieldLoader.Require] + [Desc("Has to be defined in weapons.yaml as well.")] + public readonly string Weapon = null; + + [Desc("Number of weapons fired at random 'x' cells. Negative values will result in a number equal to 'x' footprint cells fired.")] + public readonly int RandomClusterCount = -1; + + [FieldLoader.Require] + [Desc("Size of the cluster footprint")] + public readonly CVec Dimensions = CVec.Zero; + + [FieldLoader.Require] + [Desc("Cluster footprint. Cells marked as X will be attacked.", + "Cells marked as x will be attacked randomly until RandomClusterCount is reached.")] + public readonly string Footprint = string.Empty; + + WeaponInfo weapon; + + public void RulesetLoaded(Ruleset rules, WeaponInfo info) + { + if (!rules.Weapons.TryGetValue(Weapon.ToLowerInvariant(), out weapon)) + throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(Weapon.ToLowerInvariant())); + } + + public override void DoImpact(Target target, Actor firedBy, IEnumerable damageModifiers) + { + if (!target.IsValidFor(firedBy)) + return; + + var map = firedBy.World.Map; + var targetCell = map.CellContaining(target.CenterPosition); + + var targetCells = CellsMatching(targetCell, false); + foreach (var c in targetCells) + FireProjectileAtCell(map, firedBy, target, c, damageModifiers); + + if (RandomClusterCount != 0) + { + var randomTargetCells = CellsMatching(targetCell, true); + var clusterCount = RandomClusterCount < 0 ? randomTargetCells.Count() : RandomClusterCount; + if (randomTargetCells.Any()) + for (var i = 0; i < clusterCount; i++) + FireProjectileAtCell(map, firedBy, target, randomTargetCells.Random(firedBy.World.SharedRandom), damageModifiers); + } + } + + void FireProjectileAtCell(Map map, Actor firedBy, Target target, CPos targetCell, IEnumerable damageModifiers) + { + var tc = Target.FromCell(firedBy.World, targetCell); + + if (!weapon.IsValidAgainst(tc, firedBy.World, firedBy)) + return; + + var args = new ProjectileArgs + { + Weapon = weapon, + Facing = (map.CenterOfCell(targetCell) - target.CenterPosition).Yaw.Facing, + + DamageModifiers = damageModifiers.ToArray(), + InaccuracyModifiers = new int[0], + RangeModifiers = new int[0], + + Source = target.CenterPosition, + CurrentSource = () => target.CenterPosition, + SourceActor = firedBy, + PassiveTarget = map.CenterOfCell(targetCell), + GuidedTarget = tc + }; + + if (args.Weapon.Projectile != null) + { + var projectile = args.Weapon.Projectile.Create(args); + if (projectile != null) + firedBy.World.AddFrameEndTask(w => w.Add(projectile)); + + if (args.Weapon.Report != null && args.Weapon.Report.Any()) + Game.Sound.Play(SoundType.World, args.Weapon.Report, firedBy.World, target.CenterPosition); + } + } + + IEnumerable CellsMatching(CPos location, bool random) + { + var cellType = !random ? 'X' : 'x'; + var index = 0; + var footprint = Footprint.Where(c => !char.IsWhiteSpace(c)).ToArray(); + var x = location.X - (Dimensions.X - 1) / 2; + var y = location.Y - (Dimensions.Y - 1) / 2; + for (var j = 0; j < Dimensions.Y; j++) + for (var i = 0; i < Dimensions.X; i++) + if (footprint[index++] == cellType) + yield return new CPos(x + i, y + j); + } + } +} From b3788a8cf6784f4975f47937a8d33784c73fda30 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Fri, 29 Mar 2019 17:02:10 +0100 Subject: [PATCH 2/5] Add DetonationAltitude to NukePower And RemoveMissileOnDetonation boolean. Allows airburst, and optionally missile continuing until it hits the ground (without a second explosion). --- OpenRA.Mods.Common/Projectiles/NukeLaunch.cs | 29 ++++++++++++++----- .../Traits/SupportPowers/NukePower.cs | 9 +++++- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/OpenRA.Mods.Common/Projectiles/NukeLaunch.cs b/OpenRA.Mods.Common/Projectiles/NukeLaunch.cs index f8d9211abf70..231ed3b9d7c0 100644 --- a/OpenRA.Mods.Common/Projectiles/NukeLaunch.cs +++ b/OpenRA.Mods.Common/Projectiles/NukeLaunch.cs @@ -33,6 +33,8 @@ public class NukeLaunch : IProjectile, ISpatiallyPartitionable readonly WPos ascendTarget; readonly WPos descendSource; readonly WPos descendTarget; + readonly WDist detonationAltitude; + readonly bool removeOnDetonation; readonly int impactDelay; readonly int turn; readonly string trailImage; @@ -45,9 +47,11 @@ public class NukeLaunch : IProjectile, ISpatiallyPartitionable int ticks, trailTicks; int launchDelay; bool isLaunched; + bool detonated; public NukeLaunch(Player firedBy, string name, WeaponInfo weapon, string weaponPalette, string upSequence, string downSequence, - WPos launchPos, WPos targetPos, WDist velocity, int launchDelay, int impactDelay, bool skipAscent, string flashType, + WPos launchPos, WPos targetPos, WDist detonationAltitude, bool removeOnDetonation, WDist velocity, int launchDelay, int impactDelay, + bool skipAscent, string flashType, string trailImage, string[] trailSequences, string trailPalette, bool trailUsePlayerPalette, int trailDelay, int trailInterval) { this.firedBy = firedBy; @@ -74,6 +78,8 @@ public class NukeLaunch : IProjectile, ISpatiallyPartitionable ascendTarget = launchPos + offset; descendSource = targetPos + offset; descendTarget = targetPos; + this.detonationAltitude = detonationAltitude; + this.removeOnDetonation = removeOnDetonation; anim = new Animation(firedBy.World, name); @@ -100,14 +106,15 @@ public void Tick(World world) if (ticks == turn) anim.PlayRepeating(downSequence); - if (ticks < turn) + var isDescending = ticks >= turn; + if (!isDescending) pos = WPos.LerpQuadratic(ascendSource, ascendTarget, WAngle.Zero, ticks, turn); else pos = WPos.LerpQuadratic(descendSource, descendTarget, WAngle.Zero, ticks - turn, impactDelay - turn); if (!string.IsNullOrEmpty(trailImage) && --trailTicks < 0) { - var trailPos = ticks < turn ? WPos.LerpQuadratic(ascendSource, ascendTarget, WAngle.Zero, ticks - trailDelay, turn) + var trailPos = !isDescending ? WPos.LerpQuadratic(ascendSource, ascendTarget, WAngle.Zero, ticks - trailDelay, turn) : WPos.LerpQuadratic(descendSource, descendTarget, WAngle.Zero, ticks - turn - trailDelay, impactDelay - turn); world.AddFrameEndTask(w => w.Add(new SpriteEffect(trailPos, w, trailImage, trailSequences.Random(world.SharedRandom), @@ -116,23 +123,31 @@ public void Tick(World world) trailTicks = trailInterval; } - if (ticks == impactDelay) - Explode(world); + var dat = world.Map.DistanceAboveTerrain(pos); + if (ticks == impactDelay || (isDescending && dat <= detonationAltitude)) + Explode(world, ticks == impactDelay || removeOnDetonation); world.ScreenMap.Update(this, pos, anim.Image); ticks++; } - void Explode(World world) + void Explode(World world, bool removeProjectile) { - world.AddFrameEndTask(w => { w.Remove(this); w.ScreenMap.Remove(this); }); + if (removeProjectile) + world.AddFrameEndTask(w => { w.Remove(this); w.ScreenMap.Remove(this); }); + + if (detonated) + return; + weapon.Impact(Target.FromPos(pos), firedBy.PlayerActor, Enumerable.Empty()); world.WorldActor.Trait().AddEffect(20, pos, 5); foreach (var flash in world.WorldActor.TraitsImplementing()) if (flash.Info.Type == flashType) flash.Enable(-1); + + detonated = true; } public IEnumerable Render(WorldRenderer wr) diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs index 0860f30810f9..7189d9373a2d 100644 --- a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs +++ b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs @@ -35,6 +35,13 @@ class NukePowerInfo : SupportPowerInfo, IRulesetLoaded, Requires Date: Fri, 29 Mar 2019 17:06:24 +0100 Subject: [PATCH 3/5] Implement TS cluster missile warhead --- mods/ts/rules/nod-support.yaml | 3 +- mods/ts/weapons/superweapons.yaml | 172 +++++++++--------------------- 2 files changed, 50 insertions(+), 125 deletions(-) diff --git a/mods/ts/rules/nod-support.yaml b/mods/ts/rules/nod-support.yaml index 0de04cb17706..76fe2e04feb6 100644 --- a/mods/ts/rules/nod-support.yaml +++ b/mods/ts/rules/nod-support.yaml @@ -358,12 +358,13 @@ NAMISL: Icon: clustermissile ChargeInterval: 13500 Description: Cluster Missile - LongDesc: Launches a conventional warhead\nat a target location. + LongDesc: Launches an explosive cluster warhead\nat a target location. EndChargeSpeechNotification: ClusterMissileReady SelectTargetSpeechNotification: SelectTarget IncomingSpeechNotification: MissileLaunchDetected LaunchSound: icbm1.aud MissileWeapon: ClusterMissile + DetonationAltitude: 5c0 SpawnOffset: 0,427,0 DisplayTimerStances: None DisplayBeacon: False diff --git a/mods/ts/weapons/superweapons.yaml b/mods/ts/weapons/superweapons.yaml index 01ab4599c930..4291d006ee38 100644 --- a/mods/ts/weapons/superweapons.yaml +++ b/mods/ts/weapons/superweapons.yaml @@ -1,44 +1,58 @@ MultiCluster: - ReloadDelay: 80 - Range: 6c0 - Report: misl1.aud - ValidTargets: Ground + Inherits: ^DefaultMissile + ValidTargets: Ground, Water, Air Projectile: Missile - MaximumLaunchSpeed: 170 - Arm: 2 - Blockable: false - Shadow: true - Inaccuracy: 128 - Image: DRAGON - HorizontalRateOfTurn: 8 - RangeLimit: 7c204 - Palette: ra - MinimumLaunchSpeed: 75 - Speed: 384 - TerrainHeightAware: true + MaximumLaunchSpeed: 120 + Inaccuracy: 1c0 + Speed: 370 + Acceleration: 10 + MinimumLaunchAngle: -255 + MaximumLaunchAngle: 255 + RangeLimit: 10c0 + AllowSnapping: false + VerticalRateOfTurn: 16 Warhead@1Dam: SpreadDamage - Spread: 128 - Damage: 6500 - ValidTargets: Ground + Spread: 216 + Damage: 13000 + ValidTargets: Ground, Water, Air Versus: - None: 25 - Wood: 65 - Light: 75 - Heavy: 100 - Concrete: 60 + None: 100 + Wood: 85 + Light: 70 + Heavy: 35 + Concrete: 28 DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath Warhead@2Eff: CreateEffect - Explosions: large_explosion + ImpactActors: false + Explosions: large_twlt ImpactSounds: expnew09.aud - ValidTargets: Ground, Air - Warhead@3EffWater: CreateEffect - Explosions: small_watersplash - ExplosionPalette: player - ValidTargets: Water - InvalidTargets: Vehicle - Warhead@4Smu: LeaveSmudge - SmudgeType: MediumCrater - InvalidTargets: Vehicle, Building, Wall + Warhead@ResourceDestruction: DestroyResource + +ClusterMissile: + ValidTargets: Ground, Water, Air + Warhead@1Dam: SpreadDamage + Spread: 512 + Falloff: 100, 100, 0 + Damage: 26000 + ValidTargets: Ground, Water, Air + Versus: + None: 100 + Wood: 85 + Light: 70 + Heavy: 35 + Concrete: 28 + DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath + Warhead@SoundEffect: CreateEffect + Explosions: large_twlt + ExplosionPalette: effect-ignore-lighting-alpha75 + ImpactSounds: expnew19.aud + ImpactActors: false + ValidTargets: Ground Water, Air + Warhead@Cluster: FireCluster + Weapon: MultiCluster + RandomClusterCount: 10 + Dimensions: 7,7 + Footprint: __xxx__ _xxxxx_ xxxxxxx xxxxxxx xxxxxxx _xxxxx_ __xxx__ SuicideBomb: Range: 0c512 @@ -115,93 +129,3 @@ EMPulseCannon: Range: 4c0 Duration: 250 Condition: empdisable - -ClusterMissile: - ValidTargets: Ground, Water, Air - Warhead@ImpactDamage0: SpreadDamage - Spread: 1c0 - Damage: 15000 - Falloff: 1000, 368, 135, 50, 18, 7, 0 - ValidTargets: Ground, Water, Air - Versus: - Concrete: 25 - DamageTypes: Prone50Percent, TriggerProne, FireDeath - Warhead@SoundEffect0: CreateEffect - Explosions: large_explosion - ExplosionPalette: effect-ignore-lighting-alpha75 - ImpactSounds: expnew19.aud - ImpactActors: false - Warhead@ResourceDestruction0: DestroyResource - Size: 1 - Warhead@ClusterSmudges0: LeaveSmudge - SmudgeType: LargeCrater - InvalidTargets: Vehicle, Building, Wall - Size: 1 - Warhead@ClusterDamage1: SpreadDamage - Spread: 2c0 - Damage: 6000 - Falloff: 1000, 368, 135, 50, 18, 7, 0 - Delay: 5 - ValidTargets: Ground, Water, Air - Versus: - Concrete: 25 - DamageTypes: Prone50Percent, TriggerProne, FireDeath - Warhead@ResourceDestruction1: DestroyResource - Size: 2 - Delay: 5 - Warhead@ClusterSmudges1: LeaveSmudge - SmudgeType: LargeScorch - InvalidTargets: Vehicle, Building, Wall - Size: 2 - Delay: 5 - Warhead@ClusterDamage2: SpreadDamage - Spread: 3c0 - Damage: 6000 - Falloff: 1000, 368, 135, 50, 18, 7, 0 - Delay: 10 - ValidTargets: Ground, Water, Air - Versus: - Concrete: 25 - DamageTypes: Prone50Percent, TriggerProne, FireDeath - Warhead@ResourceDestruction2: DestroyResource - Size: 3 - Delay: 10 - Warhead@ClusterSmudges2: LeaveSmudge - SmudgeType: LargeScorch - InvalidTargets: Vehicle, Building, Wall - Size: 3 - Delay: 10 - Warhead@ClusterDamage3: SpreadDamage - Spread: 4c0 - Damage: 6000 - Falloff: 1000, 368, 135, 50, 18, 7, 0 - Delay: 15 - ValidTargets: Ground, Water, Air - Versus: - Concrete: 25 - DamageTypes: Prone50Percent, TriggerProne, FireDeath - Warhead@ResourceDestruction3: DestroyResource - Size: 4 - Delay: 15 - Warhead@ClusterSmudges3: LeaveSmudge - SmudgeType: MediumScorch - InvalidTargets: Vehicle, Building, Wall - Size: 4 - Delay: 15 - Warhead@ClusterDamage4: SpreadDamage - Spread: 5c0 - Damage: 6000 - Falloff: 1000, 368, 135, 50, 18, 7, 0 - Delay: 20 - ValidTargets: Ground, Water, Air - Versus: - Concrete: 25 - DamageTypes: Prone50Percent, TriggerProne, FireDeath - Warhead@ResourceDestruction4: DestroyResource - Size: 5 - Delay: 20 - Warhead@ClusterSmudges4: LeaveSmudge - SmudgeType: SmallScorch - InvalidTargets: Vehicle, Building, Wall - Size: 5 - Delay: 20 From bb8cb168c4c02b235611c0c0b07224fb9f197138 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Fri, 29 Mar 2019 20:29:57 +0100 Subject: [PATCH 4/5] Implement D2k DeathHand cluster logic --- mods/d2k/rules/structures.yaml | 4 ++- mods/d2k/sequences/misc.yaml | 2 +- mods/d2k/weapons/other.yaml | 52 +++++++++++++++++++++------------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index cc79362b19ab..cabf111ef697 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -1151,9 +1151,11 @@ palace: BeginChargeSpeechNotification: DeathHandMissilePrepping EndChargeSpeechNotification: DeathHandMissileReady LaunchSpeechNotification: MissileLaunchDetected - MissileWeapon: atomic + MissileWeapon: deathhand MissileDelay: 18 SpawnOffset: 32,816,0 + DetonationAltitude: 3c0 + RemoveMissileOnDetonation: False DisplayBeacon: True DisplayRadarPing: True CameraRange: 10c0 diff --git a/mods/d2k/sequences/misc.yaml b/mods/d2k/sequences/misc.yaml index d12b8667b268..65529baf523f 100644 --- a/mods/d2k/sequences/misc.yaml +++ b/mods/d2k/sequences/misc.yaml @@ -259,7 +259,7 @@ missile2: Facings: -32 ZOffset: 1023 -atomic: +deathhand: up: DATA.R8 Start: 2147 ZOffset: 1023 diff --git a/mods/d2k/weapons/other.yaml b/mods/d2k/weapons/other.yaml index 85c1e9663bd6..73883422ef74 100644 --- a/mods/d2k/weapons/other.yaml +++ b/mods/d2k/weapons/other.yaml @@ -106,36 +106,48 @@ Demolish: ImpactSounds: EXPLLG2.WAV ImpactActors: false -Atomic: +DeathHand: + Warhead@Cluster: FireCluster + Weapon: DeathHandCluster + RandomClusterCount: 14 + Dimensions: 3,3 + Footprint: xxx xXx xxx + Warhead@2Eff: CreateEffect + Explosions: nuke + ImpactSounds: EXPLLG2.WAV + ImpactActors: false + +DeathHandCluster: + Inherits: Debris2 + Range: 7c0 + Projectile: Bullet + Image: 120mm + TrailImage: small_trail2 + Speed: 96 + LaunchAngle: 0, 32 + Inaccuracy: 1c512 + BounceCount: 0 Warhead@1Dam: SpreadDamage - Spread: 1c0 - Falloff: 200, 100, 50, 25, 12, 0 - Damage: 27000 ##225 in vanilla but of course is a cluster bomb instead, so damage spread out + Damage: 4500 Versus: none: 90 wall: 50 - building: 75 + building: 100 wood: 60 light: 60 heavy: 60 invulnerable: 0 cy: 25 harvester: 60 - DamageTypes: Prone50Percent, TriggerProne, SoundDeath - Warhead@2Eff: CreateEffect - Explosions: nuke - ImpactSounds: EXPLLG2.WAV - ImpactActors: false - Warhead@3Concrete: DamagesConcrete - Damage: 24300 - -CrateNuke: - Inherits: Atomic - Warhead@1Dam: SpreadDamage - Spread: 320 - Falloff: 100, 60, 30, 15, 0 - Damage: 5000 - AffectsParent: true + DamageTypes: Prone50Percent, TriggerProne, ExplosionDeath + Warhead@2Smu: LeaveSmudge + SmudgeType: SandCrater, RockCrater + InvalidTargets: Vehicle, Structure + Warhead@3Eff: CreateEffect + Explosions: large_explosion + ImpactSounds: EXPLSML4.WAV + Warhead@2Concrete: DamagesConcrete + Damage: 4500 CrateExplosion: Warhead@1Dam: SpreadDamage From 4c43db930753ee519bd34c021401b4439376fc30 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Thu, 9 May 2019 20:18:40 +0200 Subject: [PATCH 5/5] Fix launch delay and offset of TS ClusterMissile --- mods/ts/rules/nod-support.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mods/ts/rules/nod-support.yaml b/mods/ts/rules/nod-support.yaml index 76fe2e04feb6..93aea5ddebab 100644 --- a/mods/ts/rules/nod-support.yaml +++ b/mods/ts/rules/nod-support.yaml @@ -364,8 +364,9 @@ NAMISL: IncomingSpeechNotification: MissileLaunchDetected LaunchSound: icbm1.aud MissileWeapon: ClusterMissile + MissileDelay: 10 DetonationAltitude: 5c0 - SpawnOffset: 0,427,0 + SpawnOffset: 72,72,0 DisplayTimerStances: None DisplayBeacon: False DisplayRadarPing: True