Merge pull request #9054 from penev92/bleed_aircraft

Merge Plane and Helicopter traits
This commit is contained in:
reaperrr
2015-10-03 01:52:30 +02:00
39 changed files with 527 additions and 558 deletions

View File

@@ -55,7 +55,7 @@ namespace OpenRA.Mods.Cnc.Traits
if (!self.IsInWorld || self.IsDead)
return;
var altitude = self.World.Map.Rules.Actors[actorType].TraitInfo<PlaneInfo>().CruiseAltitude;
var altitude = self.World.Map.Rules.Actors[actorType].TraitInfo<AircraftInfo>().CruiseAltitude;
var actor = w.CreateActor(actorType, new TypeDictionary
{
new CenterPositionInit(w.Map.CenterOfCell(startPos) + new WVec(WDist.Zero, WDist.Zero, altitude)),

View File

@@ -17,14 +17,14 @@ namespace OpenRA.Mods.Common.Activities
{
public class Fly : Activity
{
readonly Plane plane;
readonly Aircraft plane;
readonly Target target;
readonly WDist maxRange;
readonly WDist minRange;
public Fly(Actor self, Target t)
{
plane = self.Trait<Plane>();
plane = self.Trait<Aircraft>();
target = t;
}
@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Common.Activities
this.minRange = minRange;
}
public static void FlyToward(Actor self, Plane plane, int desiredFacing, WDist desiredAltitude)
public static void FlyToward(Actor self, Aircraft plane, int desiredFacing, WDist desiredAltitude)
{
desiredAltitude = new WDist(plane.CenterPosition.Z) + desiredAltitude - self.World.Map.DistanceAboveTerrain(plane.CenterPosition);

View File

@@ -10,18 +10,17 @@
using OpenRA.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Activities
{
public class FlyCircle : Activity
{
readonly Plane plane;
readonly Aircraft plane;
readonly WDist cruiseAltitude;
public FlyCircle(Actor self)
{
plane = self.Trait<Plane>();
plane = self.Trait<Aircraft>();
cruiseAltitude = plane.Info.CruiseAltitude;
}

View File

@@ -17,14 +17,14 @@ namespace OpenRA.Mods.Common.Activities
public class FlyFollow : Activity
{
Target target;
Plane plane;
Aircraft plane;
WDist minRange;
WDist maxRange;
public FlyFollow(Actor self, Target target, WDist minRange, WDist maxRange)
{
this.target = target;
plane = self.Trait<Plane>();
plane = self.Trait<Aircraft>();
this.minRange = minRange;
this.maxRange = maxRange;
}

View File

@@ -10,17 +10,16 @@
using OpenRA.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Activities
{
public class FlyOffMap : Activity
{
readonly Plane plane;
readonly Aircraft plane;
public FlyOffMap(Actor self)
{
plane = self.Trait<Plane>();
plane = self.Trait<Aircraft>();
}
public override Activity Tick(Actor self)

View File

@@ -10,20 +10,19 @@
using OpenRA.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Activities
{
public class FlyTimed : Activity
{
readonly Plane plane;
readonly Aircraft plane;
readonly WDist cruiseAltitude;
int remainingTicks;
public FlyTimed(int ticks, Actor self)
{
remainingTicks = ticks;
plane = self.Trait<Plane>();
plane = self.Trait<Aircraft>();
cruiseAltitude = plane.Info.CruiseAltitude;
}

View File

@@ -8,7 +8,6 @@
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Activities;
@@ -19,7 +18,7 @@ namespace OpenRA.Mods.Common.Activities
{
public class HeliAttack : Activity
{
readonly Helicopter helicopter;
readonly Aircraft helicopter;
readonly AttackHeli attackHeli;
readonly AmmoPool[] ammoPools;
readonly bool attackOnlyVisibleTargets;
@@ -44,7 +43,7 @@ namespace OpenRA.Mods.Common.Activities
public HeliAttack(Actor self, Target target, bool attackOnlyVisibleTargets = true)
{
Target = target;
helicopter = self.Trait<Helicopter>();
helicopter = self.Trait<Aircraft>();
attackHeli = self.Trait<AttackHeli>();
ammoPools = self.TraitsImplementing<AmmoPool>().ToArray();
this.attackOnlyVisibleTargets = attackOnlyVisibleTargets;
@@ -68,7 +67,7 @@ namespace OpenRA.Mods.Common.Activities
// If all ammo pools are depleted and none reload automatically, return to helipad to reload and then move to next activity
// TODO: This should check whether there is ammo left that is actually suitable for the target
if (ammoPools.All(x => !x.Info.SelfReloads && !x.HasAmmo()))
return Util.SequenceActivities(new HeliReturn(self), NextActivity);
return Util.SequenceActivities(new HeliReturnToBase(self), NextActivity);
var dist = target.CenterPosition - self.CenterPosition;

View File

@@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Activities
{
public class HeliFly : Activity
{
readonly Helicopter helicopter;
readonly Aircraft helicopter;
readonly Target target;
readonly WDist maxRange;
readonly WDist minRange;
@@ -25,7 +25,7 @@ namespace OpenRA.Mods.Common.Activities
public HeliFly(Actor self, Target t)
{
helicopter = self.Trait<Helicopter>();
helicopter = self.Trait<Aircraft>();
target = t;
}
@@ -36,7 +36,7 @@ namespace OpenRA.Mods.Common.Activities
this.minRange = minRange;
}
public static bool AdjustAltitude(Actor self, Helicopter helicopter, WDist targetAltitude)
public static bool AdjustAltitude(Actor self, Aircraft helicopter, WDist targetAltitude)
{
targetAltitude = new WDist(helicopter.CenterPosition.Z) + targetAltitude - self.World.Map.DistanceAboveTerrain(helicopter.CenterPosition);
@@ -105,9 +105,9 @@ namespace OpenRA.Mods.Common.Activities
public class HeliFlyAndLandWhenIdle : HeliFly
{
private readonly HelicopterInfo info;
private readonly AircraftInfo info;
public HeliFlyAndLandWhenIdle(Actor self, Target t, HelicopterInfo info)
public HeliFlyAndLandWhenIdle(Actor self, Target t, AircraftInfo info)
: base(self, t)
{
this.info = info;

View File

@@ -8,8 +8,6 @@
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
@@ -18,11 +16,11 @@ namespace OpenRA.Mods.Common.Activities
{
public class HeliFlyCircle : Activity
{
readonly Helicopter helicopter;
readonly Aircraft helicopter;
public HeliFlyCircle(Actor self)
{
helicopter = self.Trait<Helicopter>();
helicopter = self.Trait<Aircraft>();
}
public override Activity Tick(Actor self)

View File

@@ -15,14 +15,14 @@ namespace OpenRA.Mods.Common.Activities
{
public class HeliLand : Activity
{
readonly Helicopter helicopter;
readonly Aircraft helicopter;
bool requireSpace;
bool playedSound;
public HeliLand(Actor self, bool requireSpace)
{
this.requireSpace = requireSpace;
helicopter = self.Trait<Helicopter>();
helicopter = self.Trait<Aircraft>();
}
public override Activity Tick(Actor self)

View File

@@ -15,13 +15,13 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Activities
{
public class HeliReturn : Activity
public class HeliReturnToBase : Activity
{
readonly Helicopter heli;
readonly Aircraft heli;
public HeliReturn(Actor self)
public HeliReturnToBase(Actor self)
{
heli = self.Trait<Helicopter>();
heli = self.Trait<Aircraft>();
}
public Actor ChooseHelipad(Actor self)

View File

@@ -17,12 +17,12 @@ namespace OpenRA.Mods.Common.Activities
public class Land : Activity
{
readonly Target target;
readonly Plane plane;
readonly Aircraft plane;
public Land(Actor self, Target t)
{
target = t;
plane = self.Trait<Plane>();
plane = self.Trait<Aircraft>();
}
public override Activity Tick(Actor self)

View File

@@ -18,22 +18,22 @@ namespace OpenRA.Mods.Common.Activities
{
public class ReturnToBase : Activity
{
readonly Plane plane;
readonly PlaneInfo planeInfo;
readonly Aircraft plane;
readonly AircraftInfo planeInfo;
bool isCalculated;
Actor dest;
WPos w1, w2, w3;
public ReturnToBase(Actor self, Actor dest)
public ReturnToBase(Actor self, Actor dest = null)
{
this.dest = dest;
plane = self.Trait<Plane>();
planeInfo = self.Info.TraitInfo<PlaneInfo>();
plane = self.Trait<Aircraft>();
planeInfo = self.Info.TraitInfo<AircraftInfo>();
}
public static Actor ChooseAirfield(Actor self, bool unreservedOnly)
{
var rearmBuildings = self.Info.TraitInfo<PlaneInfo>().RearmBuildings;
var rearmBuildings = self.Info.TraitInfo<AircraftInfo>().RearmBuildings;
return self.World.ActorsWithTrait<Reservable>()
.Where(a => a.Actor.Owner == self.Owner)
.Where(a => rearmBuildings.Contains(a.Actor.Info.Name)
@@ -94,7 +94,6 @@ namespace OpenRA.Mods.Common.Activities
w1 = posCenter + tangentOffset;
w2 = approachCenter + tangentOffset;
w3 = approachStart;
plane.RTBPathHash = w1 + (WVec)w2 + (WVec)w3;
isCalculated = true;
}

View File

@@ -101,7 +101,7 @@
<Compile Include="Activities\Air\HeliFly.cs" />
<Compile Include="Activities\Air\HeliFlyCircle.cs" />
<Compile Include="Activities\Air\HeliLand.cs" />
<Compile Include="Activities\Air\HeliReturn.cs" />
<Compile Include="Activities\Air\HeliReturnToBase.cs" />
<Compile Include="Activities\Air\Land.cs" />
<Compile Include="Activities\Air\ResupplyAircraft.cs" />
<Compile Include="Activities\Air\ReturnToBase.cs" />
@@ -202,9 +202,11 @@
<Compile Include="Orders\RepairOrderGenerator.cs" />
<Compile Include="Orders\GlobalButtonOrderGenerator.cs" />
<Compile Include="Orders\PlaceBuildingOrderGenerator.cs" />
<Compile Include="Orders\AircraftMoveOrderTargeter.cs" />
<Compile Include="Orders\UnitOrderTargeter.cs" />
<Compile Include="Pathfinder\CellInfo.cs" />
<Compile Include="PlayerExtensions.cs" />
<Compile Include="Scripting\Properties\AircraftProperties.cs" />
<Compile Include="Scripting\ScriptUpgradesCache.cs" />
<Compile Include="Scripting\Properties\CaptureProperties.cs" />
<Compile Include="ServerTraits\ColorValidator.cs" />
@@ -235,13 +237,11 @@
<Compile Include="Scripting\Properties\DiplomacyProperties.cs" />
<Compile Include="Scripting\Properties\HarvesterProperties.cs" />
<Compile Include="Scripting\Properties\HealthProperties.cs" />
<Compile Include="Scripting\Properties\HelicopterProperties.cs" />
<Compile Include="Scripting\Properties\GeneralProperties.cs" />
<Compile Include="Scripting\Properties\GuardProperties.cs" />
<Compile Include="Scripting\Properties\MissionObjectiveProperties.cs" />
<Compile Include="Scripting\Properties\MobileProperties.cs" />
<Compile Include="Scripting\Properties\DemolitionProperties.cs" />
<Compile Include="Scripting\Properties\PlaneProperties.cs" />
<Compile Include="Scripting\Properties\PlayerProperties.cs" />
<Compile Include="Scripting\Properties\PowerProperties.cs" />
<Compile Include="Scripting\Properties\ProductionProperties.cs" />
@@ -258,8 +258,6 @@
<Compile Include="Traits\Air\AttackPlane.cs" />
<Compile Include="Traits\Air\FlyAwayOnIdle.cs" />
<Compile Include="Traits\Air\FallsToEarth.cs" />
<Compile Include="Traits\Air\Helicopter.cs" />
<Compile Include="Traits\Air\Plane.cs" />
<Compile Include="Traits\Air\ReturnOnIdle.cs" />
<Compile Include="Traits\AppearsOnRadar.cs" />
<Compile Include="Traits\Armament.cs" />

View File

@@ -0,0 +1,48 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Orders
{
class AircraftMoveOrderTargeter : IOrderTargeter
{
public string OrderID { get { return "Move"; } }
public int OrderPriority { get { return 4; } }
public bool OverrideSelection { get { return false; } }
readonly AircraftInfo info;
public AircraftMoveOrderTargeter(AircraftInfo info) { this.info = info; }
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
{
if (target.Type != TargetType.Terrain)
return false;
var location = self.World.Map.CellContaining(target.CenterPosition);
var explored = self.Owner.Shroud.IsExplored(location);
cursor = self.World.Map.Contains(location) ?
(self.World.Map.GetTerrainInfo(location).CustomCursor ?? "move") :
"move-blocked";
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
if (!explored && !info.MoveIntoShroud)
cursor = "move-blocked";
return true;
}
public bool IsQueued { get; protected set; }
}
}

View File

@@ -137,11 +137,19 @@ namespace OpenRA.Mods.Common.Scripting
}
else
{
var heli = transport.Info.TraitInfoOrDefault<HelicopterInfo>();
if (heli != null)
var aircraftInfo = transport.TraitOrDefault<Aircraft>();
if (aircraftInfo != null)
{
transport.QueueActivity(new Turn(transport, heli.InitialFacing));
transport.QueueActivity(new HeliLand(transport, true));
if (!aircraftInfo.IsPlane)
{
transport.QueueActivity(new Turn(transport, aircraftInfo.Info.InitialFacing));
transport.QueueActivity(new HeliLand(transport, true));
}
else
{
transport.QueueActivity(new Land(transport, Target.FromCell(transport.World, entryPath.Last())));
}
transport.QueueActivity(new Wait(15));
}
@@ -151,7 +159,7 @@ namespace OpenRA.Mods.Common.Scripting
transport.QueueActivity(new WaitFor(() => cargo.IsEmpty(transport)));
}
transport.QueueActivity(new Wait(heli != null ? 50 : 25));
transport.QueueActivity(new Wait(aircraftInfo != null ? 50 : 25));
}
if (exitFunc != null)

View File

@@ -16,23 +16,34 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Scripting
{
[ScriptPropertyGroup("Movement")]
public class PlaneProperties : ScriptActorProperties, Requires<PlaneInfo>
public class AircraftProperties : ScriptActorProperties, Requires<AircraftInfo>
{
public PlaneProperties(ScriptContext context, Actor self)
: base(context, self) { }
readonly bool isPlane;
public AircraftProperties(ScriptContext context, Actor self)
: base(context, self)
{
isPlane = self.Trait<Aircraft>().IsPlane;
}
[ScriptActorPropertyActivity]
[Desc("Fly within the cell grid.")]
public void Move(CPos cell)
{
Self.QueueActivity(new Fly(Self, Target.FromCell(Self.World, cell)));
if (isPlane)
Self.QueueActivity(new Fly(Self, Target.FromCell(Self.World, cell)));
else
Self.QueueActivity(new HeliFly(Self, Target.FromCell(Self.World, cell)));
}
[ScriptActorPropertyActivity]
[Desc("Return to the base, which is either the airfield given, or an auto-selected one otherwise.")]
public void ReturnToBase(Actor airfield = null)
{
Self.QueueActivity(new ReturnToBase(Self, airfield));
if (isPlane)
Self.QueueActivity(new ReturnToBase(Self, airfield));
else
Self.QueueActivity(new HeliReturnToBase(Self));
}
}
}

View File

@@ -1,31 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Scripting
{
[ScriptPropertyGroup("Movement")]
public class HelicopterProperties : ScriptActorProperties, Requires<HelicopterInfo>
{
public HelicopterProperties(ScriptContext context, Actor self)
: base(context, self) { }
[ScriptActorPropertyActivity]
[Desc("Fly within the cell grid.")]
public void Move(CPos cell)
{
Self.QueueActivity(new HeliFly(Self, Target.FromCell(Self.World, cell)));
}
}
}

View File

@@ -10,6 +10,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Activities;
using OpenRA.Mods.Common.Activities;
@@ -19,7 +20,8 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public class AircraftInfo : IPositionableInfo, IFacingInfo, IOccupySpaceInfo, ICruiseAltitudeInfo, UsesInit<LocationInit>, UsesInit<FacingInit>
public class AircraftInfo : IPositionableInfo, IFacingInfo, IOccupySpaceInfo, IMoveInfo, ICruiseAltitudeInfo,
UsesInit<LocationInit>, UsesInit<FacingInit>
{
public readonly WDist CruiseAltitude = new WDist(1280);
public readonly WDist IdealSeparation = new WDist(1706);
@@ -53,23 +55,51 @@ namespace OpenRA.Mods.Common.Traits
[Desc("The upgrades to grant to self while airborne.")]
public readonly string[] AirborneUpgrades = { };
[Desc("Can the actor hover in place mid-air? If not, then the actor will have to remain in motion (circle around).")]
public readonly bool CanHover = false;
[Desc("Will this actor try to land after it has no more commands?")]
public readonly bool LandWhenIdle = true;
[Desc("Does this actor need to turn before landing?")]
public readonly bool TurnToLand = false;
public readonly WDist LandAltitude = WDist.Zero;
[Desc("How fast this actor ascends or descends when using horizontal take off/landing.")]
public readonly WAngle MaximumPitch = WAngle.FromDegrees(10);
[Desc("How fast this actor ascends or descends when using vertical take off/landing.")]
public readonly WDist AltitudeVelocity = new WDist(43);
[Desc("Sound to play when the actor is taking off.")]
public readonly string TakeoffSound = null;
[Desc("Sound to play when the actor is landing.")]
public readonly string LandingSound = null;
public IReadOnlyDictionary<CPos, SubCell> OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any) { return new ReadOnlyDictionary<CPos, SubCell>(); }
bool IOccupySpaceInfo.SharesCell { get { return false; } }
}
public class Aircraft : IFacing, IPositionable, ISync, IIssueOrder, IOrderVoice, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyCreated, INotifyActorDisposing
public class Aircraft : ITick, ISync, IFacing, IPositionable, IMove, IIssueOrder, IResolveOrder, IOrderVoice,
INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing
{
static readonly Pair<CPos, SubCell>[] NoCells = { };
readonly AircraftInfo info;
public readonly bool IsPlane;
public readonly AircraftInfo Info;
readonly Actor self;
UpgradeManager um;
[Sync] public int Facing { get; set; }
[Sync] public WPos CenterPosition { get; private set; }
public CPos TopLeft { get { return self.World.Map.CellContaining(CenterPosition); } }
public IDisposable Reservation;
public int ROT { get { return info.ROT; } }
public int ROT { get { return Info.ROT; } }
bool airborne;
bool IsAirborne
{
get
@@ -85,21 +115,19 @@ namespace OpenRA.Mods.Common.Traits
if (um != null)
{
if (airborne)
foreach (var u in info.AirborneUpgrades)
foreach (var u in Info.AirborneUpgrades)
um.GrantUpgrade(self, u, this);
else
foreach (var u in info.AirborneUpgrades)
foreach (var u in Info.AirborneUpgrades)
um.RevokeUpgrade(self, u, this);
}
}
}
bool airborne = false;
public Aircraft(ActorInitializer init, AircraftInfo info)
{
this.info = info;
this.self = init.Self;
Info = info;
self = init.Self;
if (init.Contains<LocationInit>())
SetPosition(self, init.Get<LocationInit, CPos>());
@@ -108,10 +136,23 @@ namespace OpenRA.Mods.Common.Traits
SetPosition(self, init.Get<CenterPositionInit, WPos>());
Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing;
// TODO: HACK: This is a hack until we can properly distinquish between airplane and helicopter!
// Or until the activities get unified enough so that it doesn't matter.
IsPlane = !info.CanHover;
}
public void Created(Actor self) { um = self.TraitOrDefault<UpgradeManager>(); }
public void AddedToWorld(Actor self)
{
self.World.ActorMap.AddInfluence(self, this);
self.World.ActorMap.AddPosition(self, this);
self.World.ScreenMap.Add(self);
if (self.World.Map.DistanceAboveTerrain(CenterPosition).Length >= Info.MinAirborneAltitude)
IsAirborne = true;
}
bool firstTick = true;
public virtual void Tick(Actor self)
{
@@ -143,24 +184,39 @@ namespace OpenRA.Mods.Common.Traits
if (repulsionFacing == -1)
return;
var speed = info.RepulsionSpeed != -1 ? info.RepulsionSpeed : MovementSpeed;
var speed = Info.RepulsionSpeed != -1 ? Info.RepulsionSpeed : MovementSpeed;
SetPosition(self, CenterPosition + FlyStep(speed, repulsionFacing));
}
public virtual WVec GetRepulsionForce()
{
if (!info.Repulsable)
if (!Info.Repulsable)
return WVec.Zero;
// Repulsion only applies when we're flying!
var altitude = CenterPosition.Z;
if (altitude != info.CruiseAltitude.Length)
if (altitude != Info.CruiseAltitude.Length)
return WVec.Zero;
return self.World.FindActorsInCircle(self.CenterPosition, info.IdealSeparation)
.Where(a => !a.IsDead && a.Info.HasTraitInfo<AircraftInfo>() && a.Info.TraitInfo<AircraftInfo>().CruiseAltitude == info.CruiseAltitude)
var repulsionForce = self.World.FindActorsInCircle(self.CenterPosition, Info.IdealSeparation)
.Where(a => !a.IsDead && a.Info.HasTraitInfo<AircraftInfo>()
&& a.Info.TraitInfo<AircraftInfo>().CruiseAltitude == Info.CruiseAltitude)
.Select(GetRepulsionForce)
.Aggregate(WVec.Zero, (a, b) => a + b);
if (Info.CanHover)
return repulsionForce;
// Non-hovering actors mush always keep moving forward, so they need extra calculations.
var currentDir = FlyStep(Facing);
var length = currentDir.HorizontalLength * repulsionForce.HorizontalLength;
if (length == 0)
return WVec.Zero;
var dot = WVec.Dot(currentDir, repulsionForce) / length;
// avoid stalling the plane
return dot >= 0 ? repulsionForce : WVec.Zero;
}
public WVec GetRepulsionForce(Actor other)
@@ -170,7 +226,7 @@ namespace OpenRA.Mods.Common.Traits
var d = self.CenterPosition - other.CenterPosition;
var distSq = d.HorizontalLengthSquared;
if (distSq > info.IdealSeparation.LengthSquared)
if (distSq > Info.IdealSeparation.LengthSquared)
return WVec.Zero;
if (distSq < 1)
@@ -219,78 +275,13 @@ namespace OpenRA.Mods.Common.Traits
}
}
public void Disposing(Actor self)
{
UnReserve();
}
public void SetPosition(Actor self, WPos pos)
{
CenterPosition = pos;
if (self.IsInWorld)
{
self.World.ScreenMap.Update(self);
self.World.ActorMap.UpdatePosition(self, this);
IsAirborne = self.World.Map.DistanceAboveTerrain(CenterPosition).Length >= info.MinAirborneAltitude;
}
}
// Changes position, but not altitude
public void SetPosition(Actor self, CPos cell, SubCell subCell = SubCell.Any)
{
SetPosition(self, self.World.Map.CenterOfCell(cell) + new WVec(0, 0, CenterPosition.Z));
}
public void SetVisualPosition(Actor self, WPos pos) { SetPosition(self, pos); }
public void AddedToWorld(Actor self)
{
self.World.ActorMap.AddInfluence(self, this);
self.World.ActorMap.AddPosition(self, this);
self.World.ScreenMap.Add(self);
if (self.World.Map.DistanceAboveTerrain(CenterPosition).Length >= info.MinAirborneAltitude)
IsAirborne = true;
}
public void RemovedFromWorld(Actor self)
{
UnReserve();
self.World.ActorMap.RemoveInfluence(self, this);
self.World.ActorMap.RemovePosition(self, this);
self.World.ScreenMap.Remove(self);
IsAirborne = false;
}
public bool AircraftCanEnter(Actor a)
{
if (self.AppearsHostileTo(a))
return false;
return info.RearmBuildings.Contains(a.Info.Name)
|| info.RepairBuildings.Contains(a.Info.Name);
}
public bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any) { return false; } // TODO: Handle landing
public SubCell GetValidSubCell(SubCell preferred) { return SubCell.Invalid; }
public SubCell GetAvailableSubCell(CPos a, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, bool checkTransientActors = true)
{
// Does not use any subcell
return SubCell.Invalid;
}
public bool CanEnterCell(CPos cell, Actor ignoreActor = null, bool checkTransientActors = true) { return true; }
public bool CanEnterTargetNow(Actor self, Target target)
{
if (target.Positions.Any(p => self.World.ActorMap.GetUnitsAt(self.World.Map.CellContaining(p)).Any(a => a != self && a != target.Actor)))
return false;
var res = target.Actor.TraitOrDefault<Reservable>();
if (res == null)
return true;
UnReserve();
Reservation = res.Reserve(target.Actor, self, this);
return true;
return Info.RearmBuildings.Contains(a.Info.Name)
|| Info.RepairBuildings.Contains(a.Info.Name);
}
public int MovementSpeed
@@ -299,7 +290,7 @@ namespace OpenRA.Mods.Common.Traits
{
var modifiers = self.TraitsImplementing<ISpeedModifier>()
.Select(m => m.GetSpeedModifier());
return Util.ApplyPercentageModifiers(info.Speed, modifiers);
return Util.ApplyPercentageModifiers(Info.Speed, modifiers);
}
}
@@ -325,18 +316,151 @@ namespace OpenRA.Mods.Common.Traits
return false;
var type = self.World.Map.GetTerrainInfo(cell).Type;
return info.LandableTerrainTypes.Contains(type);
return Info.LandableTerrainTypes.Contains(type);
}
public virtual IEnumerable<Activity> GetResupplyActivities(Actor a)
{
var name = a.Info.Name;
if (info.RearmBuildings.Contains(name))
if (Info.RearmBuildings.Contains(name))
yield return new Rearm(self);
if (info.RepairBuildings.Contains(name))
if (Info.RepairBuildings.Contains(name))
yield return new Repair(a);
}
#region Implement IPositionable
public bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any) { return false; } // TODO: Handle landing
public bool CanEnterCell(CPos cell, Actor ignoreActor = null, bool checkTransientActors = true) { return true; }
public SubCell GetValidSubCell(SubCell preferred) { return SubCell.Invalid; }
public SubCell GetAvailableSubCell(CPos a, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, bool checkTransientActors = true)
{
// Does not use any subcell
return SubCell.Invalid;
}
public void SetVisualPosition(Actor self, WPos pos) { SetPosition(self, pos); }
// Changes position, but not altitude
public void SetPosition(Actor self, CPos cell, SubCell subCell = SubCell.Any)
{
SetPosition(self, self.World.Map.CenterOfCell(cell) + new WVec(0, 0, CenterPosition.Z));
}
public void SetPosition(Actor self, WPos pos)
{
CenterPosition = pos;
if (!self.IsInWorld)
return;
self.World.ScreenMap.Update(self);
self.World.ActorMap.UpdatePosition(self, this);
IsAirborne = self.World.Map.DistanceAboveTerrain(CenterPosition).Length >= Info.MinAirborneAltitude;
}
#endregion
#region Implement IMove
public Activity MoveTo(CPos cell, int nearEnough)
{
if (IsPlane)
return new FlyAndContinueWithCirclesWhenIdle(self, Target.FromCell(self.World, cell));
return new HeliFly(self, Target.FromCell(self.World, cell));
}
public Activity MoveTo(CPos cell, Actor ignoredActor)
{
if (IsPlane)
return new FlyAndContinueWithCirclesWhenIdle(self, Target.FromCell(self.World, cell));
return new HeliFly(self, Target.FromCell(self.World, cell));
}
public Activity MoveWithinRange(Target target, WDist range)
{
if (IsPlane)
return new FlyAndContinueWithCirclesWhenIdle(self, target, WDist.Zero, range);
return new HeliFly(self, target, WDist.Zero, range);
}
public Activity MoveWithinRange(Target target, WDist minRange, WDist maxRange)
{
if (IsPlane)
return new FlyAndContinueWithCirclesWhenIdle(self, target, minRange, maxRange);
return new HeliFly(self, target, minRange, maxRange);
}
public Activity MoveFollow(Actor self, Target target, WDist minRange, WDist maxRange)
{
if (IsPlane)
return new FlyFollow(self, target, minRange, maxRange);
return new Follow(self, target, minRange, maxRange);
}
public Activity MoveIntoWorld(Actor self, CPos cell, SubCell subCell = SubCell.Any)
{
if (IsPlane)
return new Fly(self, Target.FromCell(self.World, cell));
return new HeliFly(self, Target.FromCell(self.World, cell, subCell));
}
public Activity MoveToTarget(Actor self, Target target)
{
if (IsPlane)
return new Fly(self, target, WDist.FromCells(3), WDist.FromCells(5));
return Util.SequenceActivities(new HeliFly(self, target), new Turn(self, Info.InitialFacing));
}
public Activity MoveIntoTarget(Actor self, Target target)
{
if (IsPlane)
return new Land(self, target);
return new HeliLand(self, false);
}
public Activity VisualMove(Actor self, WPos fromPos, WPos toPos)
{
// TODO: Ignore repulsion when moving
if (IsPlane)
return Util.SequenceActivities(
new CallFunc(() => SetVisualPosition(self, fromPos)),
new Fly(self, Target.FromPos(toPos)));
return Util.SequenceActivities(new CallFunc(() => SetVisualPosition(self, fromPos)),
new HeliFly(self, Target.FromPos(toPos)));
}
public CPos NearestMoveableCell(CPos cell) { return cell; }
public bool IsMoving { get { return self.CenterPosition.Z > 0; } set { } }
public bool CanEnterTargetNow(Actor self, Target target)
{
if (target.Positions.Any(p => self.World.ActorMap.GetUnitsAt(self.World.Map.CellContaining(p)).Any(a => a != self && a != target.Actor)))
return false;
var res = target.Actor.TraitOrDefault<Reservable>();
if (res == null)
return true;
UnReserve();
Reservation = res.Reserve(target.Actor, self, this);
return true;
}
#endregion
#region Implement order interfaces
public IEnumerable<IOrderTargeter> Orders
{
get
@@ -344,7 +468,7 @@ namespace OpenRA.Mods.Common.Traits
yield return new EnterAlliedActorTargeter<BuildingInfo>("Enter", 5,
target => AircraftCanEnter(target), target => !Reservable.IsReserved(target));
yield return new AircraftMoveOrderTargeter(info);
yield return new AircraftMoveOrderTargeter(Info);
}
}
@@ -367,41 +491,125 @@ namespace OpenRA.Mods.Common.Traits
case "Enter":
case "ReturnToBase":
case "Stop":
return info.Voice;
return Info.Voice;
default: return null;
}
}
}
class AircraftMoveOrderTargeter : IOrderTargeter
{
public string OrderID { get { return "Move"; } }
public int OrderPriority { get { return 4; } }
public bool OverrideSelection { get { return false; } }
readonly AircraftInfo info;
public AircraftMoveOrderTargeter(AircraftInfo info) { this.info = info; }
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
public void ResolveOrder(Actor self, Order order)
{
if (target.Type != TargetType.Terrain)
return false;
if (order.OrderString == "Move")
{
var cell = self.World.Map.Clamp(order.TargetLocation);
var location = self.World.Map.CellContaining(target.CenterPosition);
var explored = self.Owner.Shroud.IsExplored(location);
cursor = self.World.Map.Contains(location) ?
(self.World.Map.GetTerrainInfo(location).CustomCursor ?? "move") :
"move-blocked";
if (!Info.MoveIntoShroud && !self.Owner.Shroud.IsExplored(cell))
return;
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
if (!order.Queued)
UnReserve();
if (!explored && !info.MoveIntoShroud)
cursor = "move-blocked";
var target = Target.FromCell(self.World, cell);
return true;
self.SetTargetLine(target, Color.Green);
if (IsPlane)
self.QueueActivity(order.Queued, new FlyAndContinueWithCirclesWhenIdle(self, target));
else
self.QueueActivity(order.Queued, new HeliFlyAndLandWhenIdle(self, target, Info));
}
else if (order.OrderString == "Enter")
{
if (!order.Queued)
UnReserve();
if (Reservable.IsReserved(order.TargetActor))
{
if (IsPlane)
self.QueueActivity(new ReturnToBase(self));
else
self.QueueActivity(new HeliReturnToBase(self));
}
else
{
self.SetTargetLine(Target.FromActor(order.TargetActor), Color.Green);
if (IsPlane)
{
self.QueueActivity(order.Queued, Util.SequenceActivities(
new ReturnToBase(self, order.TargetActor),
new ResupplyAircraft(self)));
}
else
{
var res = order.TargetActor.TraitOrDefault<Reservable>();
if (res != null)
Reservation = res.Reserve(order.TargetActor, self, this);
Action enter = () =>
{
var exit = order.TargetActor.Info.TraitInfos<ExitInfo>().FirstOrDefault();
var offset = (exit != null) ? exit.SpawnOffset : WVec.Zero;
self.QueueActivity(new HeliFly(self, Target.FromPos(order.TargetActor.CenterPosition + offset)));
self.QueueActivity(new Turn(self, Info.InitialFacing));
self.QueueActivity(new HeliLand(self, false));
self.QueueActivity(new ResupplyAircraft(self));
self.QueueActivity(new TakeOff(self));
};
self.QueueActivity(order.Queued, new CallFunc(enter));
}
}
}
else if (order.OrderString == "Stop")
{
self.CancelActivity();
if (GetActorBelow() != null)
{
self.QueueActivity(new ResupplyAircraft(self));
return;
}
UnReserve();
// TODO: Implement INotifyBecomingIdle instead
if (!IsPlane && Info.LandWhenIdle)
{
if (Info.TurnToLand)
self.QueueActivity(new Turn(self, Info.InitialFacing));
self.QueueActivity(new HeliLand(self, true));
}
}
else if (order.OrderString == "ReturnToBase")
{
UnReserve();
self.CancelActivity();
if (IsPlane)
self.QueueActivity(new ReturnToBase(self));
else
self.QueueActivity(new HeliReturnToBase(self));
self.QueueActivity(new ResupplyAircraft(self));
}
else
UnReserve();
}
public bool IsQueued { get; protected set; }
#endregion
public void RemovedFromWorld(Actor self)
{
UnReserve();
self.World.ActorMap.RemoveInfluence(self, this);
self.World.ActorMap.RemovePosition(self, this);
self.World.ScreenMap.Remove(self);
IsAirborne = false;
}
public void Disposing(Actor self)
{
UnReserve();
}
}
}

View File

@@ -1,153 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Activities;
using OpenRA.Mods.Common.Activities;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public class HelicopterInfo : AircraftInfo, IMoveInfo
{
[Desc("Allow the helicopter land after it has no more commands.")]
public readonly bool LandWhenIdle = true;
[Desc("Allow the helicopter turn before landing.")]
public readonly bool TurnToLand = false;
public readonly WDist LandAltitude = WDist.Zero;
[Desc("How fast the helicopter ascends or descends.")]
public readonly WDist AltitudeVelocity = new WDist(43);
public readonly string TakeoffSound = null;
public readonly string LandingSound = null;
public override object Create(ActorInitializer init) { return new Helicopter(init, this); }
}
public class Helicopter : Aircraft, ITick, IResolveOrder, IMove
{
public readonly HelicopterInfo Info;
Actor self;
public bool IsMoving { get { return self.CenterPosition.Z > 0; } set { } }
public Helicopter(ActorInitializer init, HelicopterInfo info)
: base(init, info)
{
self = init.Self;
Info = info;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Move")
{
var cell = self.World.Map.Clamp(order.TargetLocation);
var explored = self.Owner.Shroud.IsExplored(cell);
if (!explored && !Info.MoveIntoShroud)
return;
var target = Target.FromCell(self.World, cell);
self.SetTargetLine(target, Color.Green);
if (!order.Queued)
UnReserve();
self.QueueActivity(order.Queued, new HeliFlyAndLandWhenIdle(self, target, Info));
}
else if (order.OrderString == "Enter")
{
Action enter = () =>
{
if (Reservable.IsReserved(order.TargetActor))
self.QueueActivity(order.Queued, new HeliReturn(self));
else
{
var res = order.TargetActor.TraitOrDefault<Reservable>();
if (res != null)
Reservation = res.Reserve(order.TargetActor, self, this);
var exit = order.TargetActor.Info.TraitInfos<ExitInfo>().FirstOrDefault();
var offset = (exit != null) ? exit.SpawnOffset : WVec.Zero;
self.SetTargetLine(Target.FromActor(order.TargetActor), Color.Green);
self.QueueActivity(new HeliFly(self, Target.FromPos(order.TargetActor.CenterPosition + offset)));
self.QueueActivity(new Turn(self, Info.InitialFacing));
self.QueueActivity(new HeliLand(self, false));
self.QueueActivity(new ResupplyAircraft(self));
self.QueueActivity(new TakeOff(self));
}
};
self.QueueActivity(order.Queued, new CallFunc(enter));
if (!order.Queued)
UnReserve();
}
else
UnReserve();
if (order.OrderString == "ReturnToBase")
{
self.CancelActivity();
self.QueueActivity(new HeliReturn(self));
}
if (order.OrderString == "Stop")
{
self.CancelActivity();
if (Info.LandWhenIdle)
{
if (Info.TurnToLand)
self.QueueActivity(new Turn(self, Info.InitialFacing));
self.QueueActivity(new HeliLand(self, true));
}
}
}
public Activity MoveTo(CPos cell, int nearEnough) { return new HeliFly(self, Target.FromCell(self.World, cell)); }
public Activity MoveTo(CPos cell, Actor ignoredActor) { return new HeliFly(self, Target.FromCell(self.World, cell)); }
public Activity MoveWithinRange(Target target, WDist range) { return new HeliFly(self, target, WDist.Zero, range); }
public Activity MoveWithinRange(Target target, WDist minRange, WDist maxRange) { return new HeliFly(self, target, minRange, maxRange); }
public Activity MoveFollow(Actor self, Target target, WDist minRange, WDist maxRange) { return new Follow(self, target, minRange, maxRange); }
public CPos NearestMoveableCell(CPos cell) { return cell; }
public Activity MoveIntoWorld(Actor self, CPos cell, SubCell subCell = SubCell.Any)
{
return new HeliFly(self, Target.FromCell(self.World, cell, subCell));
}
public Activity MoveIntoTarget(Actor self, Target target) { return new HeliLand(self, false); }
public Activity MoveToTarget(Actor self, Target target)
{
return Util.SequenceActivities(new HeliFly(self, target), new Turn(self, Info.InitialFacing));
}
public Activity VisualMove(Actor self, WPos fromPos, WPos toPos)
{
// TODO: Ignore repulsion when moving
return Util.SequenceActivities(new CallFunc(() => SetVisualPosition(self, fromPos)), new HeliFly(self, Target.FromPos(toPos)));
}
public override IEnumerable<Activity> GetResupplyActivities(Actor a)
{
foreach (var b in base.GetResupplyActivities(a))
yield return b;
}
}
}

View File

@@ -1,129 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
using OpenRA.Activities;
using OpenRA.Mods.Common.Activities;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public class PlaneInfo : AircraftInfo, IMoveInfo
{
public readonly WAngle MaximumPitch = WAngle.FromDegrees(10);
public override object Create(ActorInitializer init) { return new Plane(init, this); }
}
public class Plane : Aircraft, IResolveOrder, IMove, ITick, ISync
{
public readonly PlaneInfo Info;
[Sync] public WPos RTBPathHash;
Actor self;
public bool IsMoving { get { return self.CenterPosition.Z > 0; } set { } }
public Plane(ActorInitializer init, PlaneInfo info)
: base(init, info)
{
self = init.Self;
Info = info;
}
public override WVec GetRepulsionForce()
{
var repulsionForce = base.GetRepulsionForce();
if (repulsionForce == WVec.Zero)
return WVec.Zero;
var currentDir = FlyStep(Facing);
var length = currentDir.HorizontalLength * repulsionForce.HorizontalLength;
if (length == 0)
return WVec.Zero;
var dot = WVec.Dot(currentDir, repulsionForce) / length;
// avoid stalling the plane
return dot >= 0 ? repulsionForce : WVec.Zero;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Move")
{
var cell = self.World.Map.Clamp(order.TargetLocation);
var explored = self.Owner.Shroud.IsExplored(cell);
if (!explored && !Info.MoveIntoShroud)
return;
if (!order.Queued)
UnReserve();
var target = Target.FromCell(self.World, cell);
self.SetTargetLine(target, Color.Green);
self.QueueActivity(order.Queued, new FlyAndContinueWithCirclesWhenIdle(self, target));
}
else if (order.OrderString == "Enter")
{
if (Reservable.IsReserved(order.TargetActor))
return;
if (!order.Queued)
UnReserve();
self.SetTargetLine(Target.FromOrder(self.World, order), Color.Green);
self.QueueActivity(order.Queued, Util.SequenceActivities(new ReturnToBase(self, order.TargetActor), new ResupplyAircraft(self)));
}
else if (order.OrderString == "Stop")
{
UnReserve();
self.CancelActivity();
}
else if (order.OrderString == "ReturnToBase")
{
var airfield = ReturnToBase.ChooseAirfield(self, true);
if (airfield == null)
return;
UnReserve();
self.CancelActivity();
self.SetTargetLine(Target.FromActor(airfield), Color.Green);
self.QueueActivity(new ReturnToBase(self, airfield));
self.QueueActivity(new ResupplyAircraft(self));
}
else
{
// Game.Debug("Unreserve due to unhandled order: {0}".F(order.OrderString));
UnReserve();
}
}
public Activity MoveTo(CPos cell, int nearEnough) { return Util.SequenceActivities(new Fly(self, Target.FromCell(self.World, cell)), new FlyCircle(self)); }
public Activity MoveTo(CPos cell, Actor ignoredActor) { return Util.SequenceActivities(new Fly(self, Target.FromCell(self.World, cell)), new FlyCircle(self)); }
public Activity MoveWithinRange(Target target, WDist range) { return Util.SequenceActivities(new Fly(self, target, WDist.Zero, range), new FlyCircle(self)); }
public Activity MoveWithinRange(Target target, WDist minRange, WDist maxRange)
{
return Util.SequenceActivities(new Fly(self, target, minRange, maxRange), new FlyCircle(self));
}
public Activity MoveFollow(Actor self, Target target, WDist minRange, WDist maxRange) { return new FlyFollow(self, target, minRange, maxRange); }
public CPos NearestMoveableCell(CPos cell) { return cell; }
public Activity MoveIntoWorld(Actor self, CPos cell, SubCell subCell = SubCell.Any) { return new Fly(self, Target.FromCell(self.World, cell)); }
public Activity VisualMove(Actor self, WPos fromPos, WPos toPos)
{
return Util.SequenceActivities(new CallFunc(() => SetVisualPosition(self, fromPos)), new Fly(self, Target.FromPos(toPos)));
}
public Activity MoveToTarget(Actor self, Target target) { return new Fly(self, target, WDist.FromCells(3), WDist.FromCells(5)); }
public Activity MoveIntoTarget(Actor self, Target target) { return new Land(self, target); }
}
}

View File

@@ -66,7 +66,7 @@ namespace OpenRA.Mods.Common.Traits
int totalWeight = 0;
int reservedWeight = 0;
Helicopter helicopter;
Aircraft aircraft;
CPos currentCell;
public IEnumerable<CPos> CurrentAdjacentCells { get; private set; }
@@ -116,7 +116,7 @@ namespace OpenRA.Mods.Common.Traits
public void Created(Actor self)
{
helicopter = self.TraitOrDefault<Helicopter>();
aircraft = self.TraitOrDefault<Aircraft>();
}
static int GetWeight(Actor a) { return a.Info.TraitInfo<PassengerInfo>().Weight; }
@@ -144,7 +144,7 @@ namespace OpenRA.Mods.Common.Traits
Unloading = true;
self.CancelActivity();
if (helicopter != null)
if (aircraft != null)
self.QueueActivity(new HeliLand(self, true));
self.QueueActivity(new UnloadCargo(self, true));
}
@@ -165,7 +165,7 @@ namespace OpenRA.Mods.Common.Traits
return false;
}
return !IsEmpty(self) && (helicopter == null || helicopter.CanLand(self.Location))
return !IsEmpty(self) && (aircraft == null || aircraft.CanLand(self.Location))
&& CurrentAdjacentCells != null && CurrentAdjacentCells.Any(c => Passengers.Any(p => p.Trait<IPositionable>().CanEnterCell(c)));
}

View File

@@ -61,7 +61,7 @@ namespace OpenRA.Mods.Common.Traits
if (randomize)
attackFacing = Util.QuantizeFacing(self.World.SharedRandom.Next(256), info.QuantizedFacings) * (256 / info.QuantizedFacings);
var altitude = self.World.Map.Rules.Actors[info.UnitType].TraitInfo<PlaneInfo>().CruiseAltitude.Length;
var altitude = self.World.Map.Rules.Actors[info.UnitType].TraitInfo<AircraftInfo>().CruiseAltitude.Length;
var attackRotation = WRot.FromFacing(attackFacing);
var delta = new WVec(0, -1024, 0).Rotate(attackRotation);
target = target + new WVec(0, 0, altitude);

View File

@@ -112,7 +112,7 @@ namespace OpenRA.Mods.Common.Traits
if (self.Info.HasTraitInfo<IFacingInfo>())
self.QueueActivity(new Turn(self, info.Facing));
if (self.Info.HasTraitInfo<HelicopterInfo>())
if (self.Info.HasTraitInfo<AircraftInfo>())
self.QueueActivity(new HeliLand(self, true));
foreach (var nt in self.TraitsImplementing<INotifyTransform>())

View File

@@ -111,7 +111,7 @@ namespace OpenRA.Mods.Common.Traits
var dropFacing = Util.QuantizeFacing(self.World.SharedRandom.Next(256), info.QuantizedFacings) * (256 / info.QuantizedFacings);
var delta = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(dropFacing));
var altitude = self.World.Map.Rules.Actors[info.DeliveryAircraft].TraitInfo<PlaneInfo>().CruiseAltitude.Length;
var altitude = self.World.Map.Rules.Actors[info.DeliveryAircraft].TraitInfo<AircraftInfo>().CruiseAltitude.Length;
var target = self.World.Map.CenterOfCell(p) + new WVec(0, 0, altitude);
var startEdge = target - (self.World.Map.DistanceToEdge(target, -delta) + info.Cordon).Length * delta / 1024;
var finishEdge = target + (self.World.Map.DistanceToEdge(target, delta) + info.Cordon).Length * delta / 1024;

View File

@@ -1832,9 +1832,9 @@ namespace OpenRA.Mods.Common.UtilityCommands
if (inftraits != null)
{
node.Value.Nodes.Add(new MiniYamlNode("QuantizeFacingsFromSequence", null, new List<MiniYamlNode>
{
new MiniYamlNode("Sequence", "stand"),
}));
{
new MiniYamlNode("Sequence", "stand"),
}));
}
var other = node.Value.Nodes.FirstOrDefault(x =>
@@ -2030,7 +2030,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
else
cloakedTargetTypes = new MiniYamlNode("TargetTypes", "");
node.Value.Nodes.Add(new MiniYamlNode("Targetable@UNDERWATER", "", new List<MiniYamlNode> {
node.Value.Nodes.Add(new MiniYamlNode("Targetable@UNDERWATER", "", new List<MiniYamlNode>
{
cloakedTargetTypes,
new MiniYamlNode("UpgradeTypes", "underwater"),
new MiniYamlNode("UpgradeMinEnabledLevel", "1")
@@ -2067,7 +2068,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
else
groundTargetTypes = new MiniYamlNode("TargetTypes", "");
node.Value.Nodes.Add(new MiniYamlNode("Targetable@GROUND", "", new List<MiniYamlNode> {
node.Value.Nodes.Add(new MiniYamlNode("Targetable@GROUND", "", new List<MiniYamlNode>
{
groundTargetTypes,
new MiniYamlNode("UpgradeTypes", "airborne"),
new MiniYamlNode("UpgradeMaxEnabledLevel", "0")
@@ -2175,6 +2177,18 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
if (engineVersion < 20150927)
{
if (depth == 1 && node.Key == "Plane")
node.Key = "Aircraft";
if (depth == 1 && node.Key == "Helicopter")
{
node.Key = "Aircraft";
node.Value.Nodes.Add(new MiniYamlNode("CanHover", "True"));
}
}
UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1);
}
}

View File

@@ -23,7 +23,7 @@ namespace OpenRA.Mods.D2k.Activities
readonly IMove movement;
readonly Carryable carryable;
readonly Carryall carryall;
readonly Helicopter helicopter;
readonly Aircraft aircraft;
readonly IPositionable positionable;
readonly IFacing cargoFacing;
readonly IFacing selfFacing;
@@ -39,7 +39,7 @@ namespace OpenRA.Mods.D2k.Activities
cargo = carryall.Carrying;
movement = self.Trait<IMove>();
carryable = cargo.Trait<Carryable>();
helicopter = self.Trait<Helicopter>();
aircraft = self.Trait<Aircraft>();
positionable = cargo.Trait<IPositionable>();
cargoFacing = cargo.Trait<IFacing>();
selfFacing = self.Trait<IFacing>();
@@ -95,7 +95,7 @@ namespace OpenRA.Mods.D2k.Activities
return this;
}
if (HeliFly.AdjustAltitude(self, helicopter, helicopter.Info.LandAltitude))
if (HeliFly.AdjustAltitude(self, aircraft, aircraft.Info.LandAltitude))
return this;
state = State.Release;
return Util.SequenceActivities(new Wait(15), this);

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Mods.D2k.Activities
readonly IMove movement;
readonly Carryable carryable;
readonly Carryall carryall;
readonly Helicopter helicopter;
readonly Aircraft aircraft;
readonly IFacing cargoFacing;
readonly IFacing selfFacing;
@@ -37,7 +37,7 @@ namespace OpenRA.Mods.D2k.Activities
cargoFacing = cargo.Trait<IFacing>();
movement = self.Trait<IMove>();
carryall = self.Trait<Carryall>();
helicopter = self.Trait<Helicopter>();
aircraft = self.Trait<Aircraft>();
selfFacing = self.Trait<IFacing>();
state = State.Intercept;
}
@@ -90,7 +90,7 @@ namespace OpenRA.Mods.D2k.Activities
state = State.TakeOff;
return this;
case State.TakeOff:
if (HeliFly.AdjustAltitude(self, helicopter, helicopter.Info.CruiseAltitude))
if (HeliFly.AdjustAltitude(self, aircraft, aircraft.Info.CruiseAltitude))
return this;
return NextActivity;
}

View File

@@ -50,7 +50,8 @@ namespace OpenRA.Mods.D2k.Traits
IsBusy = false;
IsCarrying = false;
var helicopter = self.Info.TraitInfoOrDefault<HelicopterInfo>();
var helicopter = self.Info.TraitInfoOrDefault<AircraftInfo>();
carryHeight = helicopter != null ? helicopter.LandAltitude : WDist.Zero;
}

View File

@@ -72,7 +72,7 @@ namespace OpenRA.Mods.RA.Traits
if (randomize)
dropFacing = Util.QuantizeFacing(self.World.SharedRandom.Next(256), info.QuantizedFacings) * (256 / info.QuantizedFacings);
var altitude = self.World.Map.Rules.Actors[info.UnitType].TraitInfo<PlaneInfo>().CruiseAltitude.Length;
var altitude = self.World.Map.Rules.Actors[info.UnitType].TraitInfo<AircraftInfo>().CruiseAltitude.Length;
var dropRotation = WRot.FromFacing(dropFacing);
var delta = new WVec(0, -1024, 0).Rotate(dropRotation);
target = target + new WVec(0, 0, altitude);

View File

@@ -9,14 +9,13 @@ TRAN:
BuildPaletteOrder: 10
Prerequisites: hpad
Queue: Aircraft.GDI, Aircraft.Nod
Helicopter:
Aircraft:
LandWhenIdle: true
ROT: 5
Speed: 140
InitialFacing: 0
LandableTerrainTypes: Clear,Rough,Road,Ore,Beach,Tiberium,BlueTiberium
AltitudeVelocity: 0c100
AirborneUpgrades: airborne
Health:
HP: 90
Armor:
@@ -53,11 +52,10 @@ HELI:
BuildPaletteOrder: 20
Prerequisites: hpad, anyhq, ~techlevel.medium
Queue: Aircraft.Nod
Helicopter:
Aircraft:
RearmBuildings: hpad
ROT: 4
Speed: 186
AirborneUpgrades: airborne
Health:
HP: 125
Armor:
@@ -105,11 +103,10 @@ ORCA:
BuildPaletteOrder: 20
Prerequisites: hpad, anyhq, ~techlevel.medium
Queue: Aircraft.GDI
Helicopter:
Aircraft:
RearmBuildings: hpad
ROT: 4
Speed: 186
AirborneUpgrades: airborne
Health:
HP: 90
Armor:
@@ -151,7 +148,7 @@ C17:
Description: Drops vehicle reinforcements on Airstrips
Valued:
Cost: 2000
Plane:
Aircraft:
ROT: 5
Speed: 326
Repulsable: False
@@ -188,7 +185,7 @@ A10:
Description: Used to deliver air strikes.
Valued:
Cost: 2000
Plane:
Aircraft:
ROT: 4
Speed: 373
Repulsable: False
@@ -221,10 +218,9 @@ TRAN.Husk:
Inherits: ^HelicopterHusk
Tooltip:
Name: Chinook Transport
Helicopter:
Aircraft:
ROT: 5
Speed: 140
AirborneUpgrades: airborne
RevealsShroud:
Range: 8c0
Type: CenterPosition
@@ -239,10 +235,9 @@ HELI.Husk:
Inherits: ^HelicopterHusk
Tooltip:
Name: Apache Longbow
Helicopter:
Aircraft:
ROT: 4
Speed: 186
AirborneUpgrades: airborne
RevealsShroud:
Range: 10c0
Type: CenterPosition
@@ -255,10 +250,9 @@ ORCA.Husk:
Inherits: ^HelicopterHusk
Tooltip:
Name: Orca
Helicopter:
Aircraft:
ROT: 4
Speed: 186
AirborneUpgrades: airborne
RevealsShroud:
Range: 10c0
Type: CenterPosition

View File

@@ -131,11 +131,12 @@
SelectionDecorations:
Selectable:
Bounds: 24,24
Helicopter:
Aircraft:
RepairBuildings: hpad
RearmBuildings:
LandWhenIdle: false
AirborneUpgrades: airborne
CanHover: True
HiddenUnderFog:
Type: CenterPosition
ActorLostNotification:
@@ -664,6 +665,9 @@
^HelicopterHusk:
Inherits: ^CommonHuskDefaults
WithShadow:
Aircraft:
AirborneUpgrades: airborne
CanHover: True
FallsToEarth:
Spins: True
Moves: False

View File

@@ -9,7 +9,7 @@ carryall.reinforce:
HP: 4800
Armor:
Type: light
Helicopter:
Aircraft:
CruiseAltitude: 2100
InitialFacing: 0
ROT: 4
@@ -21,6 +21,7 @@ carryall.reinforce:
LandAltitude: 100
LandWhenIdle: False
AirborneUpgrades: airborne
CanHover: True
Targetable@GROUND:
TargetTypes: Ground, Vehicle
UpgradeTypes: airborne
@@ -51,7 +52,7 @@ frigate:
Tooltip:
Name: Frigate
Description: Supply spacecraft
Plane:
Aircraft:
ROT: 1
Speed: 126
RepairBuildings: repair_pad
@@ -66,7 +67,6 @@ frigate:
ornithopter:
Inherits: ^Plane
Targetable:
TargetTypes: Air
AttackBomber:
Armament:
@@ -75,12 +75,13 @@ ornithopter:
HP: 900
Armor:
Type: light
Plane:
Aircraft:
ROT: 2
Speed: 189
RepairBuildings:
RearmBuildings:
Repulsable: False
CanHover: True
AmmoPool:
Ammo: 5
Tooltip:
@@ -93,7 +94,7 @@ ornithopter.husk:
Inherits: ^AircraftHusk
Tooltip:
Name: Ornithopter
Plane:
Aircraft:
ROT: 5
Speed: 189
RepairBuildings:
@@ -105,11 +106,12 @@ carryall.husk:
Inherits: ^AircraftHusk
Tooltip:
Name: Carryall
Helicopter:
Aircraft:
ROT: 4
Speed: 112
RepairBuildings:
RearmBuildings:
CanHover: True
RenderSprites:
Image: carryall

View File

@@ -131,7 +131,7 @@ waypoint:
^carryall.colorpicker:
Inherits: carryall
Helicopter:
Aircraft:
InitialFacing: 104
RenderSprites:
Image: carryall

View File

@@ -719,7 +719,7 @@ Rules:
HP: 60
Armor:
Type: Light
Plane:
Aircraft:
ROT: 5
Speed: 280
AmmoPool:

View File

@@ -6,7 +6,7 @@ BADR:
HP: 300
Armor:
Type: Light
Plane:
Aircraft:
CruiseAltitude: 2560
ROT: 5
Speed: 149
@@ -44,7 +44,7 @@ BADR.Bomber:
HP: 300
Armor:
Type: Light
Plane:
Aircraft:
CruiseAltitude: 2560
ROT: 5
Speed: 149
@@ -100,7 +100,7 @@ MIG:
LocalYaw: -40, 24
AttackPlane:
FacingTolerance: 20
Plane:
Aircraft:
CruiseAltitude: 2560
InitialFacing: 192
ROT: 4
@@ -162,7 +162,7 @@ YAK:
MuzzleSequence: muzzle
AttackPlane:
FacingTolerance: 20
Plane:
Aircraft:
CruiseAltitude: 2560
RearmBuildings: afld
InitialFacing: 192
@@ -212,7 +212,7 @@ TRAN:
RevealsShroud:
Range: 12c0
Type: CenterPosition
Helicopter:
Aircraft:
RearmBuildings: hpad
InitialFacing: 0
ROT: 5
@@ -220,6 +220,7 @@ TRAN:
LandableTerrainTypes: Clear,Rough,Road,Ore,Beach
AltitudeVelocity: 0c100
AirborneUpgrades: airborne
CanHover: True
WithRotor@PRIMARY:
Offset: -597,0,341
Sequence: rotor2
@@ -260,13 +261,14 @@ HELI:
LocalOffset: 0,213,-85
AttackHeli:
FacingTolerance: 20
Helicopter:
Aircraft:
RearmBuildings: hpad
LandWhenIdle: false
InitialFacing: 20
ROT: 4
Speed: 149
AirborneUpgrades: airborne
CanHover: True
AutoTarget:
InitialStance: HoldFire
WithRotor:
@@ -312,13 +314,14 @@ HIND:
MuzzleSequence: muzzle
AttackHeli:
FacingTolerance: 20
Helicopter:
Aircraft:
RearmBuildings: hpad
LandWhenIdle: false
InitialFacing: 20
ROT: 4
Speed: 112
AirborneUpgrades: airborne
CanHover: True
AutoTarget:
InitialStance: HoldFire
WithRotor:
@@ -342,7 +345,7 @@ U2:
HP: 2000
Armor:
Type: Heavy
Plane:
Aircraft:
CruiseAltitude: 2560
ROT: 7
Speed: 373

View File

@@ -85,10 +85,11 @@ TRAN.Husk:
Inherits: ^HelicopterHusk
Tooltip:
Name: Transport Helicopter
Helicopter:
Aircraft:
ROT: 4
Speed: 149
AirborneUpgrades: airborne
CanHover: True
WithRotor@PRIMARY:
Offset: -597,0,341
WithRotor@SECONDARY:
@@ -117,7 +118,7 @@ BADR.Husk:
Inherits: ^PlaneHusk
Tooltip:
Name: Badger
Plane:
Aircraft:
ROT: 5
Speed: 149
AirborneUpgrades: airborne
@@ -140,7 +141,7 @@ MIG.Husk:
Offset: -598,-683,0
Contrail@2:
Offset: -598,683,0
Plane:
Aircraft:
ROT: 5
Speed: 186
AirborneUpgrades: airborne
@@ -160,7 +161,7 @@ YAK.Husk:
Name: Yak Attack Plane
Contrail:
Offset: -853,0,0
Plane:
Aircraft:
ROT: 5
Speed: 149
AirborneUpgrades: airborne
@@ -178,10 +179,11 @@ HELI.Husk:
Inherits: ^HelicopterHusk
Tooltip:
Name: Longbow
Helicopter:
Aircraft:
ROT: 4
Speed: 149
AirborneUpgrades: airborne
CanHover: True
WithRotor:
Offset: 0,0,85
SmokeTrailWhenDamaged:
@@ -197,10 +199,11 @@ HIND.Husk:
Inherits: ^HelicopterHusk
Tooltip:
Name: Hind
Helicopter:
Aircraft:
ROT: 4
Speed: 112
AirborneUpgrades: airborne
CanHover: True
WithRotor:
SmokeTrailWhenDamaged:
Offset: -427,0,0
@@ -213,7 +216,7 @@ HIND.Husk:
U2.Husk:
Inherits: ^PlaneHusk
Plane:
Aircraft:
ROT: 7
Speed: 373
AirborneUpgrades: airborne

View File

@@ -4,13 +4,12 @@ DPOD:
Cost: 10
Tooltip:
Name: Drop Pod
Helicopter:
Aircraft:
LandWhenIdle: yes
ROT: 5
Speed: 149
InitialFacing: 0
LandableTerrainTypes: Clear
AirborneUpgrades: airborne
Health:
HP: 60
Armor:
@@ -40,7 +39,7 @@ DSHP:
Cost: 1000
Tooltip:
Name: Dropship
Helicopter:
Aircraft:
LandWhenIdle: yes
ROT: 5
Speed: 168
@@ -48,7 +47,6 @@ DSHP:
LandableTerrainTypes: Clear
TakeoffSound: dropup1.aud
LandingSound: dropdwn1.aud
AirborneUpgrades: airborne
Health:
HP: 200
Armor:
@@ -76,11 +74,10 @@ ORCA:
Prerequisites: ~gahpad
Selectable:
Bounds: 30,24
Helicopter:
Aircraft:
RearmBuildings: gahpad, nahpad
ROT: 5
Speed: 186
AirborneUpgrades: airborne
Health:
HP: 200
Armor:
@@ -115,7 +112,7 @@ ORCAB:
Prerequisites: ~gahpad, gatech
Selectable:
Bounds: 30,24
Plane:
Aircraft:
CruiseAltitude: 3072
MaximumPitch: 120
ROT: 3
@@ -155,7 +152,7 @@ ORCATRAN:
BuildPaletteOrder: 10
Prerequisites: ~disabled
RenderSprites:
Helicopter:
Aircraft:
LandWhenIdle: yes
ROT: 5
Speed: 84
@@ -163,7 +160,6 @@ ORCATRAN:
LandableTerrainTypes: Clear
TakeoffSound: dropup1.aud
LandingSound: dropdwn1.aud
AirborneUpgrades: airborne
Health:
HP: 200
Armor:
@@ -189,7 +185,7 @@ TRNSPORT:
Queue: Air
BuildPaletteOrder: 10
Prerequisites: ~gahpad, gadept
Helicopter:
Aircraft:
LandWhenIdle: yes
ROT: 5
Speed: 149
@@ -198,7 +194,6 @@ TRNSPORT:
TakeoffSound: dropup1.aud
LandingSound: dropdwn1.aud
AltitudeVelocity: 64
AirborneUpgrades: airborne
Health:
HP: 175
Armor:
@@ -226,7 +221,7 @@ SCRIN:
Bounds: 30,24
Voiced:
VoiceSet: Scrin
Plane:
Aircraft:
MaximumPitch: 90
ROT: 3
Speed: 168
@@ -265,11 +260,10 @@ APACHE:
Prerequisites: ~nahpad
Selectable:
Bounds: 30,24
Helicopter:
Aircraft:
RearmBuildings: gahpad, nahpad
ROT: 5
Speed: 130
AirborneUpgrades: airborne
Health:
HP: 225
Armor:

View File

@@ -482,17 +482,18 @@
^Helicopter:
Inherits: ^Aircraft
Helicopter:
Aircraft:
RepairBuildings: gadept
RearmBuildings:
LandWhenIdle: no
CruiseAltitude: 2048
Voice: Move
AirborneUpgrades: airborne
CanHover: True
^Plane:
Inherits: ^Aircraft
Plane:
Aircraft:
RepairBuildings: gadept
RearmBuildings: gahpad, nahpad
LandWhenIdle: no