Allow driving under crates and crushable units

This commit is contained in:
Gustas
2022-09-29 19:27:06 +03:00
committed by abcdefg30
parent 5abbdc37cb
commit 7f677f1842
4 changed files with 30 additions and 62 deletions

View File

@@ -830,41 +830,28 @@ namespace OpenRA.Mods.Common.Traits
public void FinishedMoving(Actor self) public void FinishedMoving(Actor self)
{ {
// Only make actor crush if it is on the ground // Only crush actors on having landed
if (!self.IsAtGroundLevel()) if (!self.IsAtGroundLevel())
return; return;
var actors = self.World.ActorMap.GetActorsAt(TopLeft).Where(a => a != self).ToList(); CrushAction(self, (notifyCrushed) => notifyCrushed.OnCrush);
if (!AnyCrushables(actors))
return;
var notifiers = actors.SelectMany(a => a.TraitsImplementing<INotifyCrushed>().Select(t => new TraitPair<INotifyCrushed>(a, t)));
foreach (var notifyCrushed in notifiers)
notifyCrushed.Trait.OnCrush(notifyCrushed.Actor, self, Info.Crushes);
}
bool AnyCrushables(List<Actor> actors)
{
var crushables = actors.SelectMany(a => a.TraitsImplementing<ICrushable>().Select(t => new TraitPair<ICrushable>(a, t))).ToList();
if (crushables.Count == 0)
return false;
foreach (var crushes in crushables)
if (crushes.Trait.CrushableBy(crushes.Actor, self, Info.Crushes))
return true;
return false;
} }
public void EnteringCell(Actor self) public void EnteringCell(Actor self)
{ {
var actors = self.World.ActorMap.GetActorsAt(TopLeft).Where(a => a != self).ToList(); CrushAction(self, (notifyCrushed) => notifyCrushed.WarnCrush);
if (!AnyCrushables(actors)) }
return;
var notifiers = actors.SelectMany(a => a.TraitsImplementing<INotifyCrushed>().Select(t => new TraitPair<INotifyCrushed>(a, t))); void CrushAction(Actor self, Func<INotifyCrushed, Action<Actor, Actor, BitSet<CrushClass>>> action)
foreach (var notifyCrushed in notifiers) {
notifyCrushed.Trait.WarnCrush(notifyCrushed.Actor, self, Info.Crushes); var crushables = self.World.ActorMap.GetActorsAt(TopLeft).Where(a => a != self)
.SelectMany(a => a.TraitsImplementing<ICrushable>().Select(t => new TraitPair<ICrushable>(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<INotifyCrushed>())
action(notifyCrushed)(crushable.Actor, self, Info.Crushes);
} }
public void AddInfluence(IEnumerable<CPos> landingCells) public void AddInfluence(IEnumerable<CPos> landingCells)

View File

@@ -103,8 +103,7 @@ namespace OpenRA.Mods.Common.Traits
void INotifyCrushed.OnCrush(Actor self, Actor crusher, BitSet<CrushClass> crushClasses) void INotifyCrushed.OnCrush(Actor self, Actor crusher, BitSet<CrushClass> crushClasses)
{ {
// Crate can only be crushed if it is not in the air. if (!crushClasses.Contains(info.CrushClass))
if (!self.IsAtGroundLevel() || !crushClasses.Contains(info.CrushClass))
return; return;
OnCrushInner(crusher); OnCrushInner(crusher);
@@ -231,13 +230,12 @@ namespace OpenRA.Mods.Common.Traits
bool ICrushable.CrushableBy(Actor self, Actor crusher, BitSet<CrushClass> crushClasses) bool ICrushable.CrushableBy(Actor self, Actor crusher, BitSet<CrushClass> crushClasses)
{ {
// Crate can only be crushed if it is not in the air. return crushClasses.Contains(info.CrushClass);
return self.IsAtGroundLevel() && crushClasses.Contains(info.CrushClass);
} }
LongBitSet<PlayerBitMask> ICrushable.CrushableBy(Actor self, BitSet<CrushClass> crushClasses) LongBitSet<PlayerBitMask> ICrushable.CrushableBy(Actor self, BitSet<CrushClass> crushClasses)
{ {
return self.IsAtGroundLevel() && crushClasses.Contains(info.CrushClass) ? self.World.AllPlayersMask : self.World.NoPlayersMask; return crushClasses.Contains(info.CrushClass) ? self.World.AllPlayersMask : self.World.NoPlayersMask;
} }
void INotifyAddedToWorld.AddedToWorld(Actor self) void INotifyAddedToWorld.AddedToWorld(Actor self)

View File

@@ -67,7 +67,7 @@ namespace OpenRA.Mods.Common.Traits
LongBitSet<PlayerBitMask> ICrushable.CrushableBy(Actor self, BitSet<CrushClass> crushClasses) LongBitSet<PlayerBitMask> ICrushable.CrushableBy(Actor self, BitSet<CrushClass> crushClasses)
{ {
if (IsTraitDisabled || !self.IsAtGroundLevel() || !Info.CrushClasses.Overlaps(crushClasses)) if (IsTraitDisabled || !Info.CrushClasses.Overlaps(crushClasses))
return self.World.NoPlayersMask; return self.World.NoPlayersMask;
return Info.CrushedByFriendlies ? self.World.AllPlayersMask : self.World.AllPlayersMask.Except(self.Owner.AlliedPlayersMask); return Info.CrushedByFriendlies ? self.World.AllPlayersMask : self.World.AllPlayersMask.Except(self.Owner.AlliedPlayersMask);
@@ -78,10 +78,6 @@ namespace OpenRA.Mods.Common.Traits
if (IsTraitDisabled) if (IsTraitDisabled)
return false; return false;
// Only make actor crushable if it is on the ground.
if (!self.IsAtGroundLevel())
return false;
if (!Info.CrushedByFriendlies && crushOwner.IsAlliedWith(self.Owner)) if (!Info.CrushedByFriendlies && crushOwner.IsAlliedWith(self.Owner))
return false; return false;

View File

@@ -567,30 +567,23 @@ namespace OpenRA.Mods.Common.Traits
foreach (var n in notifyFinishedMoving) foreach (var n in notifyFinishedMoving)
n.FinishedMoving(self, fromCell.Layer, toCell.Layer); n.FinishedMoving(self, fromCell.Layer, toCell.Layer);
// Only make actor crush if it is on the ground // Only crush actors on having landed
if (!self.IsAtGroundLevel()) if (!self.IsAtGroundLevel())
return; return;
var actors = self.World.ActorMap.GetActorsAt(ToCell, ToSubCell).Where(a => a != self).ToList(); CrushAction(self, (notifyCrushed) => notifyCrushed.OnCrush);
if (!AnyCrushables(actors))
return;
var notifiers = actors.SelectMany(a => a.TraitsImplementing<INotifyCrushed>().Select(t => new TraitPair<INotifyCrushed>(a, t)));
foreach (var notifyCrushed in notifiers)
notifyCrushed.Trait.OnCrush(notifyCrushed.Actor, self, Info.LocomotorInfo.Crushes);
} }
bool AnyCrushables(List<Actor> actors) void CrushAction(Actor self, Func<INotifyCrushed, Action<Actor, Actor, BitSet<CrushClass>>> action)
{ {
var crushables = actors.SelectMany(a => a.TraitsImplementing<ICrushable>().Select(t => new TraitPair<ICrushable>(a, t))).ToList(); var crushables = self.World.ActorMap.GetActorsAt(ToCell, ToSubCell).Where(a => a != self)
if (crushables.Count == 0) .SelectMany(a => a.TraitsImplementing<ICrushable>().Select(t => new TraitPair<ICrushable>(a, t)));
return false;
foreach (var crushes in crushables) // Only crush actors that are on the ground level
if (crushes.Trait.CrushableBy(crushes.Actor, self, Info.LocomotorInfo.Crushes)) foreach (var crushable in crushables)
return true; if (crushable.Trait.CrushableBy(crushable.Actor, self, Info.LocomotorInfo.Crushes) && crushable.Actor.IsAtGroundLevel())
foreach (var notifyCrushed in crushable.Actor.TraitsImplementing<INotifyCrushed>())
return false; action(notifyCrushed)(crushable.Actor, self, Info.LocomotorInfo.Crushes);
} }
public void AddInfluence() public void AddInfluence()
@@ -792,17 +785,11 @@ namespace OpenRA.Mods.Common.Traits
public void EnteringCell(Actor self) public void EnteringCell(Actor self)
{ {
// Only make actor crush if it is on the ground // Only crush actors on having landed
if (!self.IsAtGroundLevel()) if (!self.IsAtGroundLevel())
return; return;
var actors = self.World.ActorMap.GetActorsAt(ToCell).Where(a => a != self).ToList(); CrushAction(self, (notifyCrushed) => notifyCrushed.WarnCrush);
if (!AnyCrushables(actors))
return;
var notifiers = actors.SelectMany(a => a.TraitsImplementing<INotifyCrushed>().Select(t => new TraitPair<INotifyCrushed>(a, t)));
foreach (var notifyCrushed in notifiers)
notifyCrushed.Trait.WarnCrush(notifyCrushed.Actor, self, Info.LocomotorInfo.Crushes);
} }
public Activity MoveTo(Func<BlockedByActor, List<CPos>> pathFunc) { return new Move(self, pathFunc); } public Activity MoveTo(Func<BlockedByActor, List<CPos>> pathFunc) { return new Move(self, pathFunc); }