Add crushing logic to aircraft.

This commit is contained in:
tovl
2019-03-17 19:52:14 +01:00
committed by reaperrr
parent c633e07410
commit 560f8c26bc
9 changed files with 111 additions and 9 deletions

View File

@@ -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();

View File

@@ -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();

View File

@@ -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;
} }

View File

@@ -63,6 +63,7 @@ namespace OpenRA.Mods.Common.Activities
} }
aircraft.AddInfluence(landingCell); aircraft.AddInfluence(landingCell);
aircraft.EnteringCell(self);
landingInitiated = true; landingInitiated = true;
} }

View File

@@ -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

View File

@@ -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)));
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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