Allow queued structure rallypoints.
This commit is contained in:
@@ -188,7 +188,8 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
if (wasRepaired || isHostInvalid || (!stayOnResupplier && aircraft.Info.TakeOffOnResupply))
|
if (wasRepaired || isHostInvalid || (!stayOnResupplier && aircraft.Info.TakeOffOnResupply))
|
||||||
{
|
{
|
||||||
if (self.CurrentActivity.NextActivity == null && rp != null)
|
if (self.CurrentActivity.NextActivity == null && rp != null)
|
||||||
QueueChild(move.MoveTo(rp.Location, ignoreActor: repairableNear != null ? null : host.Actor, targetLineColor: Color.Green));
|
foreach (var cell in rp.Path)
|
||||||
|
QueueChild(move.MoveTo(cell, 1, ignoreActor: repairableNear != null ? null : host.Actor, targetLineColor: Color.Green));
|
||||||
else
|
else
|
||||||
QueueChild(new TakeOff(self));
|
QueueChild(new TakeOff(self));
|
||||||
|
|
||||||
@@ -208,7 +209,8 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
if (self.CurrentActivity.NextActivity == null)
|
if (self.CurrentActivity.NextActivity == null)
|
||||||
{
|
{
|
||||||
if (rp != null)
|
if (rp != null)
|
||||||
QueueChild(move.MoveTo(rp.Location, ignoreActor: repairableNear != null ? null : host.Actor));
|
foreach (var cell in rp.Path)
|
||||||
|
QueueChild(move.MoveTo(cell, 1, repairableNear != null ? null : host.Actor, true));
|
||||||
else if (repairableNear == null)
|
else if (repairableNear == null)
|
||||||
QueueChild(move.MoveToTarget(self, host));
|
QueueChild(move.MoveToTarget(self, host));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ namespace OpenRA.Mods.Common.Effects
|
|||||||
readonly Animation circles;
|
readonly Animation circles;
|
||||||
readonly ExitInfo[] exits;
|
readonly ExitInfo[] exits;
|
||||||
|
|
||||||
readonly WPos[] targetLine = new WPos[2];
|
List<WPos> targetLineNodes = new List<WPos> { };
|
||||||
CPos cachedLocation;
|
List<CPos> cachedLocations;
|
||||||
|
|
||||||
public RallyPointIndicator(Actor building, RallyPoint rp, ExitInfo[] exits)
|
public RallyPointIndicator(Actor building, RallyPoint rp, ExitInfo[] exits)
|
||||||
{
|
{
|
||||||
@@ -52,11 +52,13 @@ namespace OpenRA.Mods.Common.Effects
|
|||||||
if (circles != null)
|
if (circles != null)
|
||||||
circles.Tick();
|
circles.Tick();
|
||||||
|
|
||||||
if (cachedLocation != rp.Location)
|
if (cachedLocations == null || !cachedLocations.SequenceEqual(rp.Path))
|
||||||
{
|
{
|
||||||
cachedLocation = rp.Location;
|
cachedLocations = new List<CPos>(rp.Path);
|
||||||
|
targetLineNodes.Clear();
|
||||||
|
foreach (var c in cachedLocations)
|
||||||
|
targetLineNodes.Add(world.Map.CenterOfCell(c));
|
||||||
|
|
||||||
var rallyPos = world.Map.CenterOfCell(cachedLocation);
|
|
||||||
var exitPos = building.CenterPosition;
|
var exitPos = building.CenterPosition;
|
||||||
|
|
||||||
// Find closest exit
|
// Find closest exit
|
||||||
@@ -64,7 +66,7 @@ namespace OpenRA.Mods.Common.Effects
|
|||||||
foreach (var exit in exits)
|
foreach (var exit in exits)
|
||||||
{
|
{
|
||||||
var ep = building.CenterPosition + exit.SpawnOffset;
|
var ep = building.CenterPosition + exit.SpawnOffset;
|
||||||
var len = (rallyPos - ep).Length;
|
var len = (targetLineNodes[0] - ep).Length;
|
||||||
if (len < dist)
|
if (len < dist)
|
||||||
{
|
{
|
||||||
dist = len;
|
dist = len;
|
||||||
@@ -72,8 +74,7 @@ namespace OpenRA.Mods.Common.Effects
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
targetLine[0] = exitPos;
|
targetLineNodes.Insert(0, exitPos);
|
||||||
targetLine[1] = rallyPos;
|
|
||||||
|
|
||||||
if (circles != null)
|
if (circles != null)
|
||||||
circles.Play(rp.Info.CirclesSequence);
|
circles.Play(rp.Info.CirclesSequence);
|
||||||
@@ -98,10 +99,10 @@ namespace OpenRA.Mods.Common.Effects
|
|||||||
{
|
{
|
||||||
var palette = wr.Palette(rp.PaletteName);
|
var palette = wr.Palette(rp.PaletteName);
|
||||||
if (circles != null)
|
if (circles != null)
|
||||||
renderables = renderables.Concat(circles.Render(targetLine[1], palette));
|
renderables = renderables.Concat(circles.Render(targetLineNodes.Last(), palette));
|
||||||
|
|
||||||
if (flag != null)
|
if (flag != null)
|
||||||
renderables = renderables.Concat(flag.Render(targetLine[1], palette));
|
renderables = renderables.Concat(flag.Render(targetLineNodes.Last(), palette));
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderables;
|
return renderables;
|
||||||
@@ -118,7 +119,18 @@ namespace OpenRA.Mods.Common.Effects
|
|||||||
if (!building.World.Selection.Contains(building))
|
if (!building.World.Selection.Contains(building))
|
||||||
return SpriteRenderable.None;
|
return SpriteRenderable.None;
|
||||||
|
|
||||||
return new IRenderable[] { new TargetLineRenderable(targetLine, building.Owner.Color, rp.Info.LineWidth) };
|
return RenderInner(wr);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<IRenderable> RenderInner(WorldRenderer wr)
|
||||||
|
{
|
||||||
|
var prev = targetLineNodes[0];
|
||||||
|
foreach (var pos in targetLineNodes.Skip(1))
|
||||||
|
{
|
||||||
|
var targetLine = new[] { prev, pos };
|
||||||
|
prev = pos;
|
||||||
|
yield return new TargetLineRenderable(targetLine, building.Owner.Color, rp.Info.LineWidth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ namespace OpenRA.Mods.Common.Scripting
|
|||||||
[Desc("Query or set a factory's rally point.")]
|
[Desc("Query or set a factory's rally point.")]
|
||||||
public CPos RallyPoint
|
public CPos RallyPoint
|
||||||
{
|
{
|
||||||
get { return rp.Location; }
|
get { return rp.Path.Last(); }
|
||||||
set { rp.Location = value; }
|
set { rp.Path = new List<CPos> { value }; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
foreach (var rp in world.ActorsWithTrait<RallyPoint>())
|
foreach (var rp in world.ActorsWithTrait<RallyPoint>())
|
||||||
{
|
{
|
||||||
if (rp.Actor.Owner == player &&
|
if (rp.Actor.Owner == player &&
|
||||||
!IsRallyPointValid(rp.Trait.Location, rp.Actor.Info.TraitInfoOrDefault<BuildingInfo>()))
|
!IsRallyPointValid(rp.Trait.Path[0], rp.Actor.Info.TraitInfoOrDefault<BuildingInfo>()))
|
||||||
{
|
{
|
||||||
bot.QueueOrder(new Order("SetRallyPoint", rp.Actor, Target.FromCell(world, ChooseRallyLocationNear(rp.Actor)), false)
|
bot.QueueOrder(new Order("SetRallyPoint", rp.Actor, Target.FromCell(world, ChooseRallyLocationNear(rp.Actor)), false)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,23 +48,22 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
{
|
{
|
||||||
const string OrderID = "SetRallyPoint";
|
const string OrderID = "SetRallyPoint";
|
||||||
|
|
||||||
[Sync]
|
public List<CPos> Path;
|
||||||
public CPos Location;
|
|
||||||
|
|
||||||
public RallyPointInfo Info;
|
public RallyPointInfo Info;
|
||||||
public string PaletteName { get; private set; }
|
public string PaletteName { get; private set; }
|
||||||
|
|
||||||
const uint ForceSet = 1;
|
const uint ForceSet = 1;
|
||||||
|
|
||||||
public void ResetLocation(Actor self)
|
public void ResetPath(Actor self)
|
||||||
{
|
{
|
||||||
Location = self.Location + Info.Offset;
|
Path = new List<CPos> { self.Location + Info.Offset };
|
||||||
}
|
}
|
||||||
|
|
||||||
public RallyPoint(Actor self, RallyPointInfo info)
|
public RallyPoint(Actor self, RallyPointInfo info)
|
||||||
{
|
{
|
||||||
Info = info;
|
Info = info;
|
||||||
ResetLocation(self);
|
ResetPath(self);
|
||||||
PaletteName = info.IsPlayerPalette ? info.Palette + self.Owner.InternalName : info.Palette;
|
PaletteName = info.IsPlayerPalette ? info.Palette + self.Owner.InternalName : info.Palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +83,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (Info.IsPlayerPalette)
|
if (Info.IsPlayerPalette)
|
||||||
PaletteName = Info.Palette + newOwner.InternalName;
|
PaletteName = Info.Palette + newOwner.InternalName;
|
||||||
|
|
||||||
ResetLocation(self);
|
ResetPath(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IOrderTargeter> Orders
|
public IEnumerable<IOrderTargeter> Orders
|
||||||
@@ -96,7 +95,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
{
|
{
|
||||||
if (order.OrderID == OrderID)
|
if (order.OrderID == OrderID)
|
||||||
{
|
{
|
||||||
return new Order(order.OrderID, self, target, false)
|
return new Order(order.OrderID, self, target, queued)
|
||||||
{
|
{
|
||||||
SuppressVisualFeedback = true,
|
SuppressVisualFeedback = true,
|
||||||
ExtraData = ((RallyPointOrderTargeter)order).ForceSet ? ForceSet : 0
|
ExtraData = ((RallyPointOrderTargeter)order).ForceSet ? ForceSet : 0
|
||||||
@@ -108,8 +107,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == OrderID)
|
if (order.OrderString != OrderID)
|
||||||
Location = self.World.Map.CellContaining(order.Target.CenterPosition);
|
return;
|
||||||
|
|
||||||
|
if (!order.Queued)
|
||||||
|
Path.Clear();
|
||||||
|
|
||||||
|
Path.Add(self.World.Map.CellContaining(order.Target.CenterPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsForceSet(Order order)
|
public static bool IsForceSet(Order order)
|
||||||
@@ -130,12 +134,15 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public int OrderPriority { get { return 0; } }
|
public int OrderPriority { get { return 0; } }
|
||||||
public bool TargetOverridesSelection(Actor self, Target target, List<Actor> actorsAt, CPos xy, TargetModifiers modifiers) { return true; }
|
public bool TargetOverridesSelection(Actor self, Target target, List<Actor> actorsAt, CPos xy, TargetModifiers modifiers) { return true; }
|
||||||
public bool ForceSet { get; private set; }
|
public bool ForceSet { get; private set; }
|
||||||
|
public bool IsQueued { get; protected set; }
|
||||||
|
|
||||||
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)
|
||||||
{
|
{
|
||||||
if (target.Type != TargetType.Terrain)
|
if (target.Type != TargetType.Terrain)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
|
||||||
|
|
||||||
var location = self.World.Map.CellContaining(target.CenterPosition);
|
var location = self.World.Map.CellContaining(target.CenterPosition);
|
||||||
if (self.World.Map.Contains(location))
|
if (self.World.Map.Contains(location))
|
||||||
{
|
{
|
||||||
@@ -154,8 +161,6 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsQueued { get { return false; } } // unused
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (reservedForAircraft.GetActorBelow() == self)
|
if (reservedForAircraft.GetActorBelow() == self)
|
||||||
{
|
{
|
||||||
if (rallyPoint != null)
|
if (rallyPoint != null)
|
||||||
reservedFor.QueueActivity(reservedForAircraft.MoveTo(rallyPoint.Location, null, targetLineColor: Color.Green));
|
foreach (var cell in rallyPoint.Path)
|
||||||
|
reservedFor.QueueActivity(reservedForAircraft.MoveTo(cell, 1, targetLineColor: Color.Green));
|
||||||
else
|
else
|
||||||
reservedFor.QueueActivity(new TakeOff(reservedFor));
|
reservedFor.QueueActivity(new TakeOff(reservedFor));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using OpenRA.Mods.Common.Activities;
|
using OpenRA.Mods.Common.Activities;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
@@ -42,7 +43,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public virtual void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo, string productionType, TypeDictionary inits)
|
public virtual void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo, string productionType, TypeDictionary inits)
|
||||||
{
|
{
|
||||||
var exit = CPos.Zero;
|
var exit = CPos.Zero;
|
||||||
var exitLocation = CPos.Zero;
|
var exitLocations = new List<CPos>();
|
||||||
|
|
||||||
// Clone the initializer dictionary for the new actor
|
// Clone the initializer dictionary for the new actor
|
||||||
var td = new TypeDictionary();
|
var td = new TypeDictionary();
|
||||||
@@ -68,7 +69,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
initialFacing = delta.Yaw.Facing;
|
initialFacing = delta.Yaw.Facing;
|
||||||
}
|
}
|
||||||
|
|
||||||
exitLocation = rp.Value != null ? rp.Value.Location : exit;
|
exitLocations = rp.Value != null ? rp.Value.Path : new List<CPos> { exit };
|
||||||
|
|
||||||
td.Add(new LocationInit(exit));
|
td.Add(new LocationInit(exit));
|
||||||
td.Add(new CenterPositionInit(spawn));
|
td.Add(new CenterPositionInit(spawn));
|
||||||
@@ -83,7 +84,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
var move = newUnit.TraitOrDefault<IMove>();
|
var move = newUnit.TraitOrDefault<IMove>();
|
||||||
if (exitinfo != null && move != null)
|
if (exitinfo != null && move != null)
|
||||||
newUnit.QueueActivity(new AttackMoveActivity(newUnit, () => move.MoveTo(exitLocation, 1, targetLineColor: Color.OrangeRed)));
|
foreach (var cell in exitLocations)
|
||||||
|
newUnit.QueueActivity(new AttackMoveActivity(newUnit, () => move.MoveTo(cell, 1, evaluateNearestMovableCell: true, targetLineColor: Color.OrangeRed)));
|
||||||
|
|
||||||
if (!self.IsDead)
|
if (!self.IsDead)
|
||||||
foreach (var t in self.TraitsImplementing<INotifyProduction>())
|
foreach (var t in self.TraitsImplementing<INotifyProduction>())
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Traits;
|
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
@@ -49,7 +49,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
var aircraftInfo = producee.TraitInfoOrDefault<AircraftInfo>();
|
var aircraftInfo = producee.TraitInfoOrDefault<AircraftInfo>();
|
||||||
var mobileInfo = producee.TraitInfoOrDefault<MobileInfo>();
|
var mobileInfo = producee.TraitInfoOrDefault<MobileInfo>();
|
||||||
|
|
||||||
var destination = rp != null ? rp.Location : self.Location;
|
var destinations = rp != null ? rp.Path : new List<CPos> { self.Location };
|
||||||
|
|
||||||
var location = spawnLocation;
|
var location = spawnLocation;
|
||||||
if (!location.HasValue)
|
if (!location.HasValue)
|
||||||
@@ -61,7 +61,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
{
|
{
|
||||||
var locomotorInfo = mobileInfo.LocomotorInfo;
|
var locomotorInfo = mobileInfo.LocomotorInfo;
|
||||||
location = self.World.Map.ChooseClosestMatchingEdgeCell(self.Location,
|
location = self.World.Map.ChooseClosestMatchingEdgeCell(self.Location,
|
||||||
c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destination, locomotorInfo));
|
c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destinations[0], locomotorInfo));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (aircraftInfo != null)
|
if (aircraftInfo != null)
|
||||||
pos += new WVec(0, 0, aircraftInfo.CruiseAltitude.Length);
|
pos += new WVec(0, 0, aircraftInfo.CruiseAltitude.Length);
|
||||||
|
|
||||||
var initialFacing = self.World.Map.FacingBetween(location.Value, destination, 0);
|
var initialFacing = self.World.Map.FacingBetween(location.Value, destinations[0], 0);
|
||||||
|
|
||||||
self.World.AddFrameEndTask(w =>
|
self.World.AddFrameEndTask(w =>
|
||||||
{
|
{
|
||||||
@@ -91,11 +91,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
var move = newUnit.TraitOrDefault<IMove>();
|
var move = newUnit.TraitOrDefault<IMove>();
|
||||||
if (move != null)
|
if (move != null)
|
||||||
newUnit.QueueActivity(move.MoveTo(destination, 2));
|
foreach (var cell in destinations)
|
||||||
|
newUnit.QueueActivity(move.MoveTo(cell, 2, evaluateNearestMovableCell: true));
|
||||||
|
|
||||||
if (!self.IsDead)
|
if (!self.IsDead)
|
||||||
foreach (var t in self.TraitsImplementing<INotifyProduction>())
|
foreach (var t in self.TraitsImplementing<INotifyProduction>())
|
||||||
t.UnitProduced(self, newUnit, destination);
|
t.UnitProduced(self, newUnit, destinations[0]);
|
||||||
|
|
||||||
var notifyOthers = self.World.ActorsWithTrait<INotifyOtherProduction>();
|
var notifyOthers = self.World.ActorsWithTrait<INotifyOtherProduction>();
|
||||||
foreach (var notify in notifyOthers)
|
foreach (var notify in notifyOthers)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using OpenRA.Activities;
|
using OpenRA.Activities;
|
||||||
using OpenRA.Mods.Common.Activities;
|
using OpenRA.Mods.Common.Activities;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
@@ -102,7 +103,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public override void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo, string productionType, TypeDictionary inits)
|
public override void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo, string productionType, TypeDictionary inits)
|
||||||
{
|
{
|
||||||
var exit = CPos.Zero;
|
var exit = CPos.Zero;
|
||||||
var exitLocation = CPos.Zero;
|
var exitLocations = new List<CPos>();
|
||||||
|
|
||||||
var info = (ProductionParadropInfo)Info;
|
var info = (ProductionParadropInfo)Info;
|
||||||
var actorType = info.ActorType;
|
var actorType = info.ActorType;
|
||||||
@@ -122,7 +123,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
var initialFacing = exitinfo.Facing < 0 ? (to - spawn).Yaw.Facing : exitinfo.Facing;
|
var initialFacing = exitinfo.Facing < 0 ? (to - spawn).Yaw.Facing : exitinfo.Facing;
|
||||||
|
|
||||||
exitLocation = rp.Value != null ? rp.Value.Location : exit;
|
exitLocations = rp.Value != null ? rp.Value.Path : new List<CPos> { exit };
|
||||||
|
|
||||||
td.Add(new LocationInit(exit));
|
td.Add(new LocationInit(exit));
|
||||||
td.Add(new CenterPositionInit(spawn));
|
td.Add(new CenterPositionInit(spawn));
|
||||||
@@ -137,7 +138,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
var move = newUnit.TraitOrDefault<IMove>();
|
var move = newUnit.TraitOrDefault<IMove>();
|
||||||
if (move != null)
|
if (move != null)
|
||||||
newUnit.QueueActivity(new AttackMoveActivity(newUnit, () => move.MoveTo(exitLocation, 1, targetLineColor: Color.OrangeRed)));
|
foreach (var cell in exitLocations)
|
||||||
|
newUnit.QueueActivity(new AttackMoveActivity(newUnit, () => move.MoveTo(cell, 1, evaluateNearestMovableCell: true, targetLineColor: Color.OrangeRed)));
|
||||||
|
|
||||||
if (!self.IsDead)
|
if (!self.IsDead)
|
||||||
foreach (var t in self.TraitsImplementing<INotifyProduction>())
|
foreach (var t in self.TraitsImplementing<INotifyProduction>())
|
||||||
|
|||||||
Reference in New Issue
Block a user