Add a new INotifyCrushed interface
This commit is contained in:
@@ -303,11 +303,16 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public interface ICrushable
|
public interface ICrushable
|
||||||
{
|
{
|
||||||
void OnCrush(Actor crusher);
|
|
||||||
void WarnCrush(Actor crusher);
|
|
||||||
bool CrushableBy(HashSet<string> crushClasses, Player owner);
|
bool CrushableBy(HashSet<string> crushClasses, Player owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RequireExplicitImplementation]
|
||||||
|
public interface INotifyCrushed
|
||||||
|
{
|
||||||
|
void OnCrush(Actor self, Actor crusher, HashSet<string> crushClasses);
|
||||||
|
void WarnCrush(Actor self, Actor crusher, HashSet<string> crushClasses);
|
||||||
|
}
|
||||||
|
|
||||||
public interface ITraitInfoInterface { }
|
public interface ITraitInfoInterface { }
|
||||||
public interface ITraitInfo : ITraitInfoInterface { object Create(ActorInitializer init); }
|
public interface ITraitInfo : ITraitInfoInterface { object Create(ActorInitializer init); }
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
bool IOccupySpaceInfo.SharesCell { get { return false; } }
|
bool IOccupySpaceInfo.SharesCell { get { return false; } }
|
||||||
}
|
}
|
||||||
|
|
||||||
class Crate : ITick, IPositionable, ICrushable, ISync, INotifyParachuteLanded, INotifyAddedToWorld, INotifyRemovedFromWorld
|
class Crate : ITick, IPositionable, ICrushable, ISync,
|
||||||
|
INotifyParachuteLanded, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyCrushed
|
||||||
{
|
{
|
||||||
readonly Actor self;
|
readonly Actor self;
|
||||||
readonly CrateInfo info;
|
readonly CrateInfo info;
|
||||||
@@ -56,36 +57,14 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
SetPosition(self, init.Get<LocationInit, CPos>());
|
SetPosition(self, init.Get<LocationInit, CPos>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WarnCrush(Actor crusher) { }
|
void INotifyCrushed.WarnCrush(Actor self, Actor crusher, HashSet<string> crushClasses) { }
|
||||||
|
|
||||||
public void OnCrush(Actor crusher)
|
void INotifyCrushed.OnCrush(Actor self, Actor crusher, HashSet<string> crushClasses)
|
||||||
{
|
{
|
||||||
if (collected)
|
if (!CrushableBy(crushClasses, crusher.Owner))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var crateActions = self.TraitsImplementing<CrateAction>();
|
OnCrushInner(crusher);
|
||||||
|
|
||||||
self.Dispose();
|
|
||||||
collected = true;
|
|
||||||
|
|
||||||
if (crateActions.Any())
|
|
||||||
{
|
|
||||||
var shares = crateActions.Select(a => Pair.New(a, a.GetSelectionSharesOuter(crusher)));
|
|
||||||
|
|
||||||
var totalShares = shares.Sum(a => a.Second);
|
|
||||||
var n = self.World.SharedRandom.Next(totalShares);
|
|
||||||
|
|
||||||
foreach (var s in shares)
|
|
||||||
{
|
|
||||||
if (n < s.Second)
|
|
||||||
{
|
|
||||||
s.First.Activate(crusher);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
n -= s.Second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnLanded()
|
public void OnLanded()
|
||||||
@@ -110,11 +89,41 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
// Destroy the crate if none of the units in the cell are valid collectors
|
// Destroy the crate if none of the units in the cell are valid collectors
|
||||||
if (collector != null)
|
if (collector != null)
|
||||||
OnCrush(collector);
|
OnCrushInner(collector);
|
||||||
else
|
else
|
||||||
self.Dispose();
|
self.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnCrushInner(Actor crusher)
|
||||||
|
{
|
||||||
|
if (collected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var crateActions = self.TraitsImplementing<CrateAction>();
|
||||||
|
|
||||||
|
self.Dispose();
|
||||||
|
collected = true;
|
||||||
|
|
||||||
|
if (crateActions.Any())
|
||||||
|
{
|
||||||
|
var shares = crateActions.Select(a => Pair.New(a, a.GetSelectionSharesOuter(crusher)));
|
||||||
|
|
||||||
|
var totalShares = shares.Sum(a => a.Second);
|
||||||
|
var n = self.World.SharedRandom.Next(totalShares);
|
||||||
|
|
||||||
|
foreach (var s in shares)
|
||||||
|
{
|
||||||
|
if (n < s.Second)
|
||||||
|
{
|
||||||
|
s.First.Activate(crusher);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
n -= s.Second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Tick(Actor self)
|
public void Tick(Actor self)
|
||||||
{
|
{
|
||||||
if (info.Lifetime != 0 && self.IsInWorld && ++ticks >= info.Lifetime * 25)
|
if (info.Lifetime != 0 && self.IsInWorld && ++ticks >= info.Lifetime * 25)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public object Create(ActorInitializer init) { return new Crushable(init.Self, this); }
|
public object Create(ActorInitializer init) { return new Crushable(init.Self, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
class Crushable : ICrushable
|
class Crushable : ICrushable, INotifyCrushed
|
||||||
{
|
{
|
||||||
readonly Actor self;
|
readonly Actor self;
|
||||||
readonly CrushableInfo info;
|
readonly CrushableInfo info;
|
||||||
@@ -40,16 +40,23 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
this.info = info;
|
this.info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WarnCrush(Actor crusher)
|
void INotifyCrushed.WarnCrush(Actor self, Actor crusher, HashSet<string> crushClasses)
|
||||||
{
|
{
|
||||||
|
if (!CrushableBy(crushClasses, crusher.Owner))
|
||||||
|
return;
|
||||||
|
|
||||||
var mobile = self.TraitOrDefault<Mobile>();
|
var mobile = self.TraitOrDefault<Mobile>();
|
||||||
if (mobile != null && self.World.SharedRandom.Next(100) <= info.WarnProbability)
|
if (mobile != null && self.World.SharedRandom.Next(100) <= info.WarnProbability)
|
||||||
mobile.Nudge(self, crusher, true);
|
mobile.Nudge(self, crusher, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnCrush(Actor crusher)
|
void INotifyCrushed.OnCrush(Actor self, Actor crusher, HashSet<string> crushClasses)
|
||||||
{
|
{
|
||||||
|
if (!CrushableBy(crushClasses, crusher.Owner))
|
||||||
|
return;
|
||||||
|
|
||||||
Game.Sound.Play(info.CrushSound, crusher.CenterPosition);
|
Game.Sound.Play(info.CrushSound, crusher.CenterPosition);
|
||||||
|
|
||||||
var wda = self.TraitsImplementing<WithDeathAnimation>()
|
var wda = self.TraitsImplementing<WithDeathAnimation>()
|
||||||
.FirstOrDefault(s => s.Info.CrushedSequence != null);
|
.FirstOrDefault(s => s.Info.CrushedSequence != null);
|
||||||
if (wda != null)
|
if (wda != null)
|
||||||
|
|||||||
@@ -594,10 +594,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (!self.IsAtGroundLevel())
|
if (!self.IsAtGroundLevel())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var crushables = self.World.ActorMap.GetActorsAt(ToCell).Where(a => a != self)
|
var notifiers = self.World.ActorMap.GetActorsAt(ToCell).Where(a => a != self)
|
||||||
.SelectMany(a => a.TraitsImplementing<ICrushable>().Where(b => b.CrushableBy(Info.Crushes, self.Owner)));
|
.SelectMany(a => a.TraitsImplementing<INotifyCrushed>().Select(t => new TraitPair<INotifyCrushed>(a, t)));
|
||||||
foreach (var crushable in crushables)
|
foreach (var notifyCrushed in notifiers)
|
||||||
crushable.WarnCrush(self);
|
notifyCrushed.Trait.WarnCrush(notifyCrushed.Actor, self, Info.Crushes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FinishedMoving(Actor self)
|
public void FinishedMoving(Actor self)
|
||||||
@@ -606,10 +606,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (!self.IsAtGroundLevel())
|
if (!self.IsAtGroundLevel())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var crushables = self.World.ActorMap.GetActorsAt(ToCell).Where(a => a != self)
|
var notifiers = self.World.ActorMap.GetActorsAt(ToCell).Where(a => a != self)
|
||||||
.SelectMany(a => a.TraitsImplementing<ICrushable>().Where(c => c.CrushableBy(Info.Crushes, self.Owner)));
|
.SelectMany(a => a.TraitsImplementing<INotifyCrushed>().Select(t => new TraitPair<INotifyCrushed>(a, t)));
|
||||||
foreach (var crushable in crushables)
|
foreach (var notifyCrushed in notifiers)
|
||||||
crushable.OnCrush(self);
|
notifyCrushed.Trait.OnCrush(notifyCrushed.Actor, self, Info.Crushes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int MovementSpeedForCell(Actor self, CPos cell)
|
public int MovementSpeedForCell(Actor self, CPos cell)
|
||||||
|
|||||||
@@ -20,24 +20,25 @@ namespace OpenRA.Mods.RA.Traits
|
|||||||
public readonly bool AvoidFriendly = true;
|
public readonly bool AvoidFriendly = true;
|
||||||
public readonly HashSet<string> DetonateClasses = new HashSet<string>();
|
public readonly HashSet<string> DetonateClasses = new HashSet<string>();
|
||||||
|
|
||||||
public object Create(ActorInitializer init) { return new Mine(init, this); }
|
public object Create(ActorInitializer init) { return new Mine(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
class Mine : ICrushable
|
class Mine : ICrushable, INotifyCrushed
|
||||||
{
|
{
|
||||||
readonly Actor self;
|
|
||||||
readonly MineInfo info;
|
readonly MineInfo info;
|
||||||
|
|
||||||
public Mine(ActorInitializer init, MineInfo info)
|
public Mine(MineInfo info)
|
||||||
{
|
{
|
||||||
self = init.Self;
|
|
||||||
this.info = info;
|
this.info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WarnCrush(Actor crusher) { }
|
void INotifyCrushed.WarnCrush(Actor self, Actor crusher, HashSet<string> crushClasses) { }
|
||||||
|
|
||||||
public void OnCrush(Actor crusher)
|
void INotifyCrushed.OnCrush(Actor self, Actor crusher, HashSet<string> crushClasses)
|
||||||
{
|
{
|
||||||
|
if (!CrushableBy(crushClasses, crusher.Owner))
|
||||||
|
return;
|
||||||
|
|
||||||
if (crusher.Info.HasTraitInfo<MineImmuneInfo>() || (self.Owner.Stances[crusher.Owner] == Stance.Ally && info.AvoidFriendly))
|
if (crusher.Info.HasTraitInfo<MineImmuneInfo>() || (self.Owner.Stances[crusher.Owner] == Stance.Ally && info.AvoidFriendly))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user