From e8dd85419fe978bad0afdabaa44ef20e2643b362 Mon Sep 17 00:00:00 2001 From: dnqbob Date: Fri, 21 Oct 2022 19:56:16 +0800 Subject: [PATCH] add Autocrusher for baby visc --- OpenRA.Mods.Common/Traits/AutoCrusher.cs | 79 ++++++++++++++++++++++++ mods/ts/rules/critters.yaml | 2 + 2 files changed, 81 insertions(+) create mode 100644 OpenRA.Mods.Common/Traits/AutoCrusher.cs diff --git a/OpenRA.Mods.Common/Traits/AutoCrusher.cs b/OpenRA.Mods.Common/Traits/AutoCrusher.cs new file mode 100644 index 0000000000..4856e662c9 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/AutoCrusher.cs @@ -0,0 +1,79 @@ +#region Copyright & License Information +/* + * Copyright (c) The OpenRA Developers and Contributors + * 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.Linq; +using OpenRA.Mods.Common.Activities; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + class AutoCrusherInfo : PausableConditionalTraitInfo, Requires + { + [Desc("Maximum range to scan for targets.")] + public readonly WDist ScanRadius = WDist.FromCells(5); + + [Desc("The minimal amount of ticks to wait between scanning for targets.")] + public readonly int MinimumScanTimeInterval = 10; + + [Desc("The maximal amount of ticks to wait between scanning for targets.")] + public readonly int MaximumScanTimeInterval = 15; + + [Desc("The crush class(es) that can be automatically crushed.")] + public readonly BitSet CrushClasses = default; + + [Desc("Player relationships the owner of the actor needs to get targeted.")] + public readonly PlayerRelationship TargetRelationships = PlayerRelationship.Ally | PlayerRelationship.Neutral | PlayerRelationship.Enemy; + + public override object Create(ActorInitializer init) { return new AutoCrusher(init.Self, this); } + } + + class AutoCrusher : PausableConditionalTrait, INotifyIdle + { + int nextScanTime; + readonly IMoveInfo moveInfo; + readonly bool isAircraft; + protected readonly IMove Move; + + public AutoCrusher(Actor self, AutoCrusherInfo info) + : base(info) + { + Move = self.Trait(); + moveInfo = self.Info.TraitInfo(); + nextScanTime = self.World.SharedRandom.Next(Info.MinimumScanTimeInterval, Info.MaximumScanTimeInterval); + isAircraft = Move is Aircraft; + } + + void INotifyIdle.TickIdle(Actor self) + { + if (nextScanTime-- > 0) + return; + + // TODO: Add a proper Cloak and Disguise detection here. + var crushableActor = self.World.FindActorsInCircle(self.CenterPosition, Info.ScanRadius) + .Where(a => a != self && !a.IsDead && a.IsInWorld && + self.Location != a.Location && a.IsAtGroundLevel() && + Info.TargetRelationships.HasRelationship(self.Owner.RelationshipWith(a.Owner)) && + a.TraitsImplementing().Any(c => c.CrushableBy(a, self, Info.CrushClasses))) + .ClosestTo(self); // TODO: Make it use shortest pathfinding distance instead + + if (crushableActor == null) + return; + + if (isAircraft) + self.QueueActivity(new Land(self, Target.FromActor(crushableActor), targetLineColor: moveInfo.GetTargetLineColor())); + else + self.QueueActivity(Move.MoveTo(crushableActor.Location, targetLineColor: moveInfo.GetTargetLineColor())); + + nextScanTime = self.World.SharedRandom.Next(Info.MinimumScanTimeInterval, Info.MaximumScanTimeInterval); + } + } +} diff --git a/mods/ts/rules/critters.yaml b/mods/ts/rules/critters.yaml index c6545ff6d5..367aa82f63 100644 --- a/mods/ts/rules/critters.yaml +++ b/mods/ts/rules/critters.yaml @@ -75,6 +75,8 @@ VISC_SML: CrushClasses: visceroid-fusing WarnProbability: 0 CrushedByFriendlies: True + AutoCrusher: + CrushClasses: visceroid-fusing TransformCrusherOnCrush: IntoActor: visc_lrg CrushClasses: visceroid-fusing