From a691f2ebac0118fed4a6c966ce9b319a36966ba1 Mon Sep 17 00:00:00 2001 From: Gustas <37534529+PunkPun@users.noreply.github.com> Date: Sat, 1 Oct 2022 15:47:23 +0300 Subject: [PATCH] Give husks the ability to crush --- OpenRA.Mods.Common/Traits/Husk.cs | 57 ++++++++++++++++++++++++++++--- mods/cnc/rules/defaults.yaml | 3 ++ mods/d2k/rules/defaults.yaml | 1 + mods/d2k/rules/husks.yaml | 4 +++ mods/ra/rules/defaults.yaml | 1 + mods/ra/rules/husks.yaml | 4 +++ 6 files changed, 65 insertions(+), 5 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/Husk.cs b/OpenRA.Mods.Common/Traits/Husk.cs index c9db6ef105..06c3112f18 100644 --- a/OpenRA.Mods.Common/Traits/Husk.cs +++ b/OpenRA.Mods.Common/Traits/Husk.cs @@ -9,8 +9,10 @@ */ #endregion +using System; using System.Collections.Generic; using System.Linq; +using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Primitives; using OpenRA.Traits; @@ -18,13 +20,17 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Spawns remains of a husk actor with the correct facing.")] - public class HuskInfo : TraitInfo, IPositionableInfo, IFacingInfo, IActorPreviewInitInfo + public class HuskInfo : TraitInfo, IPositionableInfo, IFacingInfo, IActorPreviewInitInfo, IRulesetLoaded { public readonly HashSet AllowedTerrain = new(); [Desc("Facing to use for actor previews (map editor, color picker, etc)")] public readonly WAngle PreviewFacing = new(384); + [LocomotorReference] + [Desc("Used to define crushes. Locomotor must be defined on the World actor.")] + public readonly string Locomotor = null; + IEnumerable IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type) { yield return new FacingInit(PreviewFacing); @@ -47,6 +53,15 @@ namespace OpenRA.Mods.Common.Traits // all places relevant for husks check IPositionable.CanEnterCell instead, so we can safely set this to true. return true; } + + public LocomotorInfo LocomotorInfo { get; private set; } + public void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + if (string.IsNullOrEmpty(Locomotor)) + return; + + LocomotorInfo = rules.Actors[SystemActors.World].TraitInfos().FirstOrDefault(li => li.Name == Locomotor); + } } public class Husk : IPositionable, IFacing, ISync, INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, @@ -95,10 +110,7 @@ namespace OpenRA.Mods.Common.Traits void INotifyCreated.Created(Actor self) { - var distance = (finalPosition - CenterPosition).Length; - if (dragSpeed > 0 && distance > 0) - self.QueueActivity(new Drag(self, CenterPosition, finalPosition, distance / dragSpeed)); - + self.QueueActivity(new DragAndCrush(self, info.LocomotorInfo, dragSpeed, finalPosition)); notifyCenterPositionChanged = self.TraitsImplementing().ToArray(); } @@ -181,4 +193,39 @@ namespace OpenRA.Mods.Common.Traits public HuskSpeedInit(int value) : base(value) { } } + + public class DragAndCrush : Activity + { + readonly LocomotorInfo info; + + public DragAndCrush(Actor self, LocomotorInfo info, int dragSpeed, WPos finalPosition) + { + this.info = info; + + var distance = (finalPosition - self.CenterPosition).Length; + if (dragSpeed > 0 && distance > 0) + self.QueueActivity(new Drag(self, self.CenterPosition, finalPosition, distance / dragSpeed)); + } + + protected override void OnFirstRun(Actor self) + { + if (self.IsAtGroundLevel()) + CrushAction(self, self.CenterPosition, (notifyCrushed) => notifyCrushed.OnCrush); + } + + void CrushAction(Actor self, WPos position, Func>> action) + { + if (info == null || !info.Crushes.Any()) + return; + + var crushables = self.World.ActorMap.GetActorsAt(self.World.Map.CellContaining(position)).Where(a => a != self) + .SelectMany(a => a.TraitsImplementing().Select(t => new TraitPair(a, t))); + + // Only crush actors that are on the ground level. + foreach (var crushable in crushables) + if (crushable.Trait.CrushableBy(crushable.Actor, self, info.Crushes) && crushable.Actor.IsAtGroundLevel()) + foreach (var notifyCrushed in crushable.Actor.TraitsImplementing()) + action(notifyCrushed)(crushable.Actor, self, info.Crushes); + } + } } diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index f5aa21dc27..0c4de51c94 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -1069,6 +1069,7 @@ Inherits: ^CommonHuskDefaults Husk: AllowedTerrain: Clear, Rough, Road, Tiberium, BlueTiberium, Beach + Locomotor: tracked Targetable: RequiresForceFire: true TargetTypes: Ground, Husk @@ -1097,6 +1098,8 @@ ^LightHusk: Inherits: ^Husk + Husk: + Locomotor: wheeled Health: HP: 4000 diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index 9415fed25c..e0a93e04a2 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -299,6 +299,7 @@ Inherits: ^Husk Husk: AllowedTerrain: Sand, Rock, Transition, Concrete, Spice, SpiceSand, SpiceBlobs, Dune + Locomotor: tank Targetable: TargetTypes: Ground, Vehicle RequiresForceFire: true diff --git a/mods/d2k/rules/husks.yaml b/mods/d2k/rules/husks.yaml index 851cc0fad9..e84700d7ee 100644 --- a/mods/d2k/rules/husks.yaml +++ b/mods/d2k/rules/husks.yaml @@ -32,6 +32,8 @@ missile_tank.husk: sonic_tank.husk: Inherits: ^VehicleHusk + Husk: + Locomotor: vehicle Tooltip: Name: Sonic Tank (Destroyed) TransformOnCapture: @@ -39,6 +41,8 @@ sonic_tank.husk: devastator.husk: Inherits: ^VehicleHusk + Husk: + Locomotor: devastator Health: HP: 1250 Tooltip: diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 978add4fab..a92902ca98 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -1048,6 +1048,7 @@ Inherits@2: ^ClassicFacingSpriteActor Husk: AllowedTerrain: Clear, Rough, Road, Ore, Gems, Beach + Locomotor: tracked WithIdleOverlay@Burns: Image: fire Sequence: 1 diff --git a/mods/ra/rules/husks.yaml b/mods/ra/rules/husks.yaml index 4317efa42d..a21fc21315 100644 --- a/mods/ra/rules/husks.yaml +++ b/mods/ra/rules/husks.yaml @@ -26,6 +26,8 @@ 4TNK.Husk: Inherits: ^Husk + Husk: + Locomotor: heavytracked Tooltip: Name: Husk (Mammoth Tank) ThrowsParticle@turret: @@ -72,6 +74,8 @@ MCV.Husk: MGG.Husk: Inherits: ^Husk + Husk: + Locomotor: wheeled Tooltip: Name: Husk (Mobile Gap Generator) ThrowsParticle@spinner: