Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make AutoCrusher aware of Cloak and Disguise #21115

Merged
merged 3 commits into from
Oct 13, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 33 additions & 9 deletions OpenRA.Mods.Common/Traits/AutoCrusher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,31 @@ sealed class AutoCrusherInfo : PausableConditionalTraitInfo, Requires<IMoveInfo>
public override object Create(ActorInitializer init) { return new AutoCrusher(init.Self, this); }
}

sealed class AutoCrusher : PausableConditionalTrait<AutoCrusherInfo>, INotifyIdle
sealed class AutoCrusher : ConditionalTrait<AutoCrusherInfo>, INotifyIdle
{
int nextScanTime;
readonly IMoveInfo moveInfo;
readonly bool isAircraft;
readonly bool ignoresDisguise;
readonly IMove move;

public AutoCrusher(Actor self, AutoCrusherInfo info)
: base(info)
{
move = self.Trait<IMove>();
moveInfo = self.Info.TraitInfo<IMoveInfo>();
nextScanTime = self.World.SharedRandom.Next(Info.MinimumScanTimeInterval, Info.MaximumScanTimeInterval);
isAircraft = move is Aircraft;
ignoresDisguise = self.Info.HasTraitInfo<IgnoresDisguiseInfo>();
}

void INotifyIdle.TickIdle(Actor self)
{
if (nextScanTime-- > 0)
if (IsTraitDisabled || nextScanTime-- > 0)
abcdefg30 marked this conversation as resolved.
Show resolved Hide resolved
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<ICrushable>().Any(c => c.CrushableBy(a, self, Info.CrushClasses)))
.ClosestToWithPathFrom(self);
.Where(a => IsValidCrushTarget(self, a))
.ClosestToWithPathFrom(self); // TODO: Make it use shortest pathfinding distance instead

if (crushableActor == null)
return;
Expand All @@ -75,5 +72,32 @@ void INotifyIdle.TickIdle(Actor self)

nextScanTime = self.World.SharedRandom.Next(Info.MinimumScanTimeInterval, Info.MaximumScanTimeInterval);
}

bool IsValidCrushTarget(Actor self, Actor target)
{
if (target == self || target.IsDead || !target.IsInWorld || self.Location != target.Location || !target.IsAtGroundLevel())
return false;

var targetRelationship = self.Owner.RelationshipWith(target.Owner);
var effectiveOwner = target.EffectiveOwner?.Owner;
if (effectiveOwner != null && !ignoresDisguise && targetRelationship != PlayerRelationship.Ally)
{
// Check effective relationships if the target is disguised and we cannot see through the disguise. (By ignoring it or by being an ally.)
if (!Info.TargetRelationships.HasRelationship(self.Owner.RelationshipWith(effectiveOwner)))
return false;
}
else if (!Info.TargetRelationships.HasRelationship(targetRelationship))
return false;

if (target.TraitsImplementing<Cloak>().Any(c => !c.IsTraitDisabled && !c.IsVisible(target, self.Owner)))
return false;

return target.TraitsImplementing<ICrushable>().Any(c => c.CrushableBy(target, self, Info.CrushClasses));
}

protected override void TraitEnabled(Actor self)
{
nextScanTime = self.World.SharedRandom.Next(Info.MinimumScanTimeInterval, Info.MaximumScanTimeInterval);
}
}
}