Add crushing logic to aircraft.
This commit is contained in:
@@ -105,6 +105,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
soundPlayed = true;
|
soundPlayed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We are taking off, so remove influence in ground cells.
|
||||||
if (self.IsAtGroundLevel())
|
if (self.IsAtGroundLevel())
|
||||||
aircraft.RemoveInfluence();
|
aircraft.RemoveInfluence();
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
soundPlayed = true;
|
soundPlayed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We are taking off, so remove influence in ground cells.
|
||||||
if (self.IsAtGroundLevel())
|
if (self.IsAtGroundLevel())
|
||||||
aircraft.RemoveInfluence();
|
aircraft.RemoveInfluence();
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
using OpenRA.Activities;
|
using OpenRA.Activities;
|
||||||
using OpenRA.Mods.Common.Traits;
|
using OpenRA.Mods.Common.Traits;
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.Activities
|
namespace OpenRA.Mods.Common.Activities
|
||||||
{
|
{
|
||||||
@@ -37,6 +38,13 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
|
if (ChildActivity != null)
|
||||||
|
{
|
||||||
|
ChildActivity = ActivityUtils.RunActivity(self, ChildActivity);
|
||||||
|
if (ChildActivity != null)
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsCanceling)
|
if (IsCanceling)
|
||||||
{
|
{
|
||||||
aircraft.RemoveInfluence();
|
aircraft.RemoveInfluence();
|
||||||
@@ -48,11 +56,13 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
var landingCell = self.Location;
|
var landingCell = self.Location;
|
||||||
if (!aircraft.CanLand(landingCell, ignoreActor))
|
if (!aircraft.CanLand(landingCell, ignoreActor))
|
||||||
{
|
{
|
||||||
|
QueueChild(self, new Wait(25), true);
|
||||||
self.NotifyBlocker(landingCell);
|
self.NotifyBlocker(landingCell);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
aircraft.AddInfluence(landingCell);
|
aircraft.AddInfluence(landingCell);
|
||||||
|
aircraft.EnteringCell(self);
|
||||||
landingInitiated = true;
|
landingInitiated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
}
|
}
|
||||||
|
|
||||||
aircraft.AddInfluence(landingCell);
|
aircraft.AddInfluence(landingCell);
|
||||||
|
aircraft.EnteringCell(self);
|
||||||
landingInitiated = true;
|
landingInitiated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
[Desc("Can the actor be ordered to move in to shroud?")]
|
[Desc("Can the actor be ordered to move in to shroud?")]
|
||||||
public readonly bool MoveIntoShroud = true;
|
public readonly bool MoveIntoShroud = true;
|
||||||
|
|
||||||
|
[Desc("e.g. crate, wall, infantry")]
|
||||||
|
public readonly BitSet<CrushClass> Crushes = default(BitSet<CrushClass>);
|
||||||
|
|
||||||
|
[Desc("Types of damage that are caused while crushing. Leave empty for no damage types.")]
|
||||||
|
public readonly BitSet<DamageType> CrushDamageTypes = default(BitSet<DamageType>);
|
||||||
|
|
||||||
[VoiceReference] public readonly string Voice = "Action";
|
[VoiceReference] public readonly string Voice = "Action";
|
||||||
|
|
||||||
[GrantedConditionReference]
|
[GrantedConditionReference]
|
||||||
@@ -166,6 +172,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing, INotifyBecomingIdle,
|
INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing, INotifyBecomingIdle,
|
||||||
IActorPreviewInitModifier, IIssueDeployOrder, IObservesVariables
|
IActorPreviewInitModifier, IIssueDeployOrder, IObservesVariables
|
||||||
{
|
{
|
||||||
|
static readonly Pair<CPos, SubCell>[] NoCells = { };
|
||||||
|
|
||||||
public readonly AircraftInfo Info;
|
public readonly AircraftInfo Info;
|
||||||
readonly Actor self;
|
readonly Actor self;
|
||||||
|
|
||||||
@@ -183,7 +191,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public Actor ReservedActor { get; private set; }
|
public Actor ReservedActor { get; private set; }
|
||||||
public bool MayYieldReservation { get; private set; }
|
public bool MayYieldReservation { get; private set; }
|
||||||
public bool ForceLanding { get; private set; }
|
public bool ForceLanding { get; private set; }
|
||||||
CPos landingCell;
|
CPos? landingCell;
|
||||||
|
|
||||||
bool airborne;
|
bool airborne;
|
||||||
bool cruising;
|
bool cruising;
|
||||||
@@ -495,7 +503,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public Pair<CPos, SubCell>[] OccupiedCells()
|
public Pair<CPos, SubCell>[] OccupiedCells()
|
||||||
{
|
{
|
||||||
if (!self.IsAtGroundLevel())
|
if (!self.IsAtGroundLevel())
|
||||||
return new[] { Pair.New(landingCell, SubCell.FullCell) };
|
{
|
||||||
|
if (landingCell.HasValue)
|
||||||
|
return new[] { Pair.New(landingCell.Value, SubCell.FullCell) };
|
||||||
|
|
||||||
|
return NoCells;
|
||||||
|
}
|
||||||
|
|
||||||
return new[] { Pair.New(TopLeft, SubCell.FullCell) };
|
return new[] { Pair.New(TopLeft, SubCell.FullCell) };
|
||||||
}
|
}
|
||||||
@@ -517,16 +530,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
foreach (var otherActor in self.World.ActorMap.GetActorsAt(cell))
|
foreach (var otherActor in self.World.ActorMap.GetActorsAt(cell))
|
||||||
{
|
if (IsBlockedBy(self, otherActor, ignoreActor))
|
||||||
if (otherActor != ignoreActor)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var otherActor in self.World.ActorMap.GetActorsAt(cell))
|
foreach (var otherActor in self.World.ActorMap.GetActorsAt(cell))
|
||||||
{
|
|
||||||
if (AircraftCanEnter(otherActor))
|
if (AircraftCanEnter(otherActor))
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
var type = self.World.Map.GetTerrainInfo(cell).Type;
|
var type = self.World.Map.GetTerrainInfo(cell).Type;
|
||||||
return Info.LandableTerrainTypes.Contains(type);
|
return Info.LandableTerrainTypes.Contains(type);
|
||||||
@@ -542,6 +551,35 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return repairable != null && repairable.Info.RepairActors.Contains(host.Info.Name) && self.GetDamageState() != DamageState.Undamaged;
|
return repairable != null && repairable.Info.RepairActors.Contains(host.Info.Name) && self.GetDamageState() != DamageState.Undamaged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsBlockedBy(Actor self, Actor otherActor, Actor ignoreActor)
|
||||||
|
{
|
||||||
|
// We are not blocked by the actor we are ignoring.
|
||||||
|
if (otherActor == self || otherActor == ignoreActor)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// PERF: Only perform ITemporaryBlocker trait look-up if mod/map rules contain any actors that are temporary blockers
|
||||||
|
if (self.World.RulesContainTemporaryBlocker)
|
||||||
|
{
|
||||||
|
// If there is a temporary blocker in our path, but we can remove it, we are not blocked.
|
||||||
|
var temporaryBlocker = otherActor.TraitOrDefault<ITemporaryBlocker>();
|
||||||
|
if (temporaryBlocker != null && temporaryBlocker.CanRemoveBlockage(otherActor, self))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we cannot crush the other actor in our way, we are blocked.
|
||||||
|
if (Info.Crushes.IsEmpty)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If the other actor in our way cannot be crushed, we are blocked.
|
||||||
|
// PERF: Avoid LINQ.
|
||||||
|
var crushables = otherActor.TraitsImplementing<ICrushable>();
|
||||||
|
foreach (var crushable in crushables)
|
||||||
|
if (crushable.CrushableBy(otherActor, self, Info.Crushes))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual IEnumerable<Activity> GetResupplyActivities(Actor a)
|
public virtual IEnumerable<Activity> GetResupplyActivities(Actor a)
|
||||||
{
|
{
|
||||||
// The ResupplyAircraft activity guarantees that we're on the helipad/repair depot
|
// The ResupplyAircraft activity guarantees that we're on the helipad/repair depot
|
||||||
@@ -589,7 +627,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
}
|
}
|
||||||
else if (!Info.CanHover && !atLandAltitude)
|
else if (!Info.CanHover && !atLandAltitude)
|
||||||
self.QueueActivity(new FlyCircle(self, -1, Info.IdleTurnSpeed > -1 ? Info.IdleTurnSpeed : TurnSpeed));
|
self.QueueActivity(new FlyCircle(self, -1, Info.IdleTurnSpeed > -1 ? Info.IdleTurnSpeed : TurnSpeed));
|
||||||
else if (atLandAltitude && !CanLand(self.Location, self) && ReservedActor == null)
|
else if (atLandAltitude && !CanLand(self.Location) && ReservedActor == null)
|
||||||
self.QueueActivity(new TakeOff(self));
|
self.QueueActivity(new TakeOff(self));
|
||||||
else if (Info.CanHover && self.Info.HasTraitInfo<AutoCarryallInfo>() && Info.IdleTurnSpeed > -1)
|
else if (Info.CanHover && self.Info.HasTraitInfo<AutoCarryallInfo>() && Info.IdleTurnSpeed > -1)
|
||||||
{
|
{
|
||||||
@@ -629,16 +667,59 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
self.World.UpdateMaps(self, this);
|
self.World.UpdateMaps(self, this);
|
||||||
|
|
||||||
var altitude = self.World.Map.DistanceAboveTerrain(CenterPosition);
|
var altitude = self.World.Map.DistanceAboveTerrain(CenterPosition);
|
||||||
|
|
||||||
var isAirborne = altitude.Length >= Info.MinAirborneAltitude;
|
var isAirborne = altitude.Length >= Info.MinAirborneAltitude;
|
||||||
if (isAirborne && !airborne)
|
if (isAirborne && !airborne)
|
||||||
OnAirborneAltitudeReached();
|
OnAirborneAltitudeReached();
|
||||||
else if (!isAirborne && airborne)
|
else if (!isAirborne && airborne)
|
||||||
OnAirborneAltitudeLeft();
|
OnAirborneAltitudeLeft();
|
||||||
|
|
||||||
var isCruising = altitude == Info.CruiseAltitude;
|
var isCruising = altitude == Info.CruiseAltitude;
|
||||||
if (isCruising && !cruising)
|
if (isCruising && !cruising)
|
||||||
OnCruisingAltitudeReached();
|
OnCruisingAltitudeReached();
|
||||||
else if (!isCruising && cruising)
|
else if (!isCruising && cruising)
|
||||||
OnCruisingAltitudeLeft();
|
OnCruisingAltitudeLeft();
|
||||||
|
|
||||||
|
FinishedMoving(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinishedMoving(Actor self)
|
||||||
|
{
|
||||||
|
// Only make actor crush if it is on the ground
|
||||||
|
if (!self.IsAtGroundLevel())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var actors = self.World.ActorMap.GetActorsAt(TopLeft).Where(a => a != self).ToList();
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var actors = self.World.ActorMap.GetActorsAt(TopLeft).Where(a => a != self).ToList();
|
||||||
|
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.Crushes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddInfluence(CPos landingCell)
|
public void AddInfluence(CPos landingCell)
|
||||||
@@ -652,6 +733,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
{
|
{
|
||||||
if (self.IsInWorld)
|
if (self.IsInWorld)
|
||||||
self.World.ActorMap.RemoveInfluence(self, this);
|
self.World.ActorMap.RemoveInfluence(self, this);
|
||||||
|
|
||||||
|
landingCell = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !IsEmpty(self) && (aircraft == null || aircraft.CanLand(self.Location, self))
|
return !IsEmpty(self) && (aircraft == null || aircraft.CanLand(self.Location))
|
||||||
&& CurrentAdjacentCells != null && CurrentAdjacentCells.Any(c => Passengers.Any(p => p.Trait<IPositionable>().CanEnterCell(c, null, immediate)));
|
&& CurrentAdjacentCells != null && CurrentAdjacentCells.Any(c => Passengers.Any(p => p.Trait<IPositionable>().CanEnterCell(c, null, immediate)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ TRAN:
|
|||||||
TurnSpeed: 5
|
TurnSpeed: 5
|
||||||
Speed: 150
|
Speed: 150
|
||||||
LandableTerrainTypes: Clear,Rough,Road,Ore,Beach,Tiberium,BlueTiberium
|
LandableTerrainTypes: Clear,Rough,Road,Ore,Beach,Tiberium,BlueTiberium
|
||||||
|
Crushes: crate, infantry
|
||||||
AltitudeVelocity: 0c100
|
AltitudeVelocity: 0c100
|
||||||
Health:
|
Health:
|
||||||
HP: 9000
|
HP: 9000
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ TRAN:
|
|||||||
TurnSpeed: 5
|
TurnSpeed: 5
|
||||||
Speed: 128
|
Speed: 128
|
||||||
LandableTerrainTypes: Clear,Rough,Road,Ore,Beach,Gems
|
LandableTerrainTypes: Clear,Rough,Road,Ore,Beach,Gems
|
||||||
|
Crushes: crate, mine, infantry
|
||||||
AltitudeVelocity: 0c58
|
AltitudeVelocity: 0c58
|
||||||
WithIdleOverlay@ROTOR1AIR:
|
WithIdleOverlay@ROTOR1AIR:
|
||||||
Offset: 597,0,213
|
Offset: 597,0,213
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ DPOD:
|
|||||||
Speed: 149
|
Speed: 149
|
||||||
InitialFacing: 0
|
InitialFacing: 0
|
||||||
LandableTerrainTypes: Clear,Road,Rail,DirtRoad,Rough,Tiberium,BlueTiberium,Veins
|
LandableTerrainTypes: Clear,Road,Rail,DirtRoad,Rough,Tiberium,BlueTiberium,Veins
|
||||||
|
Crushes: crate, infantry
|
||||||
Health:
|
Health:
|
||||||
HP: 6000
|
HP: 6000
|
||||||
Armor:
|
Armor:
|
||||||
@@ -46,6 +47,7 @@ DSHP:
|
|||||||
Speed: 168
|
Speed: 168
|
||||||
InitialFacing: 0
|
InitialFacing: 0
|
||||||
LandableTerrainTypes: Clear,Road,Rail,DirtRoad,Rough,Tiberium,BlueTiberium,Veins
|
LandableTerrainTypes: Clear,Road,Rail,DirtRoad,Rough,Tiberium,BlueTiberium,Veins
|
||||||
|
Crushes: crate, infantry
|
||||||
TakeoffSounds: dropup1.aud
|
TakeoffSounds: dropup1.aud
|
||||||
LandingSounds: dropdwn1.aud
|
LandingSounds: dropdwn1.aud
|
||||||
IdealSeparation: 1275
|
IdealSeparation: 1275
|
||||||
@@ -192,6 +194,7 @@ ORCATRAN:
|
|||||||
Speed: 84
|
Speed: 84
|
||||||
InitialFacing: 0
|
InitialFacing: 0
|
||||||
LandableTerrainTypes: Clear,Road,Rail,DirtRoad,Rough,Tiberium,BlueTiberium,Veins
|
LandableTerrainTypes: Clear,Road,Rail,DirtRoad,Rough,Tiberium,BlueTiberium,Veins
|
||||||
|
Crushes: crate, infantry
|
||||||
TakeoffSounds: orcaup1.aud
|
TakeoffSounds: orcaup1.aud
|
||||||
LandingSounds: orcadwn1.aud
|
LandingSounds: orcadwn1.aud
|
||||||
IdealSeparation: 1275
|
IdealSeparation: 1275
|
||||||
@@ -230,6 +233,7 @@ TRNSPORT:
|
|||||||
Speed: 149
|
Speed: 149
|
||||||
InitialFacing: 0
|
InitialFacing: 0
|
||||||
LandableTerrainTypes: Clear,Road,Rail,DirtRoad,Rough,Tiberium,BlueTiberium,Veins
|
LandableTerrainTypes: Clear,Road,Rail,DirtRoad,Rough,Tiberium,BlueTiberium,Veins
|
||||||
|
Crushes: crate, infantry
|
||||||
TakeoffSounds: dropup1.aud
|
TakeoffSounds: dropup1.aud
|
||||||
LandingSounds: dropdwn1.aud
|
LandingSounds: dropdwn1.aud
|
||||||
AltitudeVelocity: 64
|
AltitudeVelocity: 64
|
||||||
|
|||||||
Reference in New Issue
Block a user