Allow driving under crates and crushable units
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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); }
|
||||||
|
|||||||
Reference in New Issue
Block a user