Rewrite Aircraft movement using world coords.

This commit is contained in:
Paul Chote
2013-07-21 16:41:35 +12:00
parent c3f04cc32e
commit 57adaf46b0
21 changed files with 252 additions and 230 deletions

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -19,10 +19,10 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Air
{
public class AircraftInfo : ITraitInfo, IFacingInfo, IOccupySpaceInfo, UsesInit<AltitudeInit>, UsesInit<LocationInit>, UsesInit<FacingInit>
{
public readonly int CruiseAltitude = 30;
[ActorReference]
public readonly string[] RepairBuildings = { "fix" };
[ActorReference]
@@ -38,47 +38,37 @@ namespace OpenRA.Mods.RA.Air
public class Aircraft : IFacing, IPositionable, ISync, INotifyKilled, IIssueOrder, IOrderVoice
{
public IDisposable reservation;
static readonly Pair<CPos, SubCell>[] NoCells = new Pair<CPos, SubCell>[] { };
public void UnReserve()
{
if (reservation != null)
{
reservation.Dispose();
reservation = null;
}
}
readonly AircraftInfo info;
readonly Actor self;
public void Killed(Actor self, AttackInfo e)
{
UnReserve();
}
protected readonly Actor self;
[Sync] public int Facing { get; set; }
[Sync] public int Altitude { get; set; }
[Sync] public PSubPos SubPxPosition;
public WPos CenterPosition { get { return PxPosition.ToWPos(Altitude); } }
public PPos PxPosition { get { return SubPxPosition.ToPPos(); } }
public CPos TopLeft { get { return PxPosition.ToCPos(); } }
readonly AircraftInfo Info;
[Sync] public WPos CenterPosition { get; private set; }
public CPos TopLeft { get { return CenterPosition.ToCPos(); } }
public IDisposable Reservation;
public int ROT { get { return info.ROT; } }
public Aircraft(ActorInitializer init, AircraftInfo info)
{
this.info = info;
this.self = init.self;
if (init.Contains<LocationInit>())
this.SubPxPosition = Util.CenterOfCell( init.Get<LocationInit, CPos>() ).ToPSubPos();
SetPosition(self, init.Get<LocationInit, CPos>());
this.Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing;
this.Altitude = init.Contains<AltitudeInit>() ? init.Get<AltitudeInit,int>() : 0;
Info = info;
if (init.Contains<AltitudeInit>())
{
var z = init.Get<AltitudeInit, int>() * 1024 / Game.CellSize;
SetPosition(self, CenterPosition + new WVec(0, 0, z - CenterPosition.Z));
}
}
public Actor GetActorBelow()
{
if (Altitude != 0)
if (self.CenterPosition.Z != 0)
return null; // not on the ground.
return self.World.FindActorsInBox(self.CenterPosition, self.CenterPosition)
@@ -94,29 +84,39 @@ namespace OpenRA.Mods.RA.Air
var res = afld.Trait<Reservable>();
if (res != null)
reservation = res.Reserve(afld, self, this);
Reservation = res.Reserve(afld, self, this);
}
public int ROT { get { return Info.ROT; } }
public void UnReserve()
{
if (Reservation != null)
{
Reservation.Dispose();
Reservation = null;
}
}
public void Killed(Actor self, AttackInfo e)
{
UnReserve();
}
public void SetPosition(Actor self, CPos cell)
{
SubPxPosition = Util.CenterOfCell(cell).ToPSubPos();
}
public void SetPosition(Actor self, WPos pos)
{
// TODO: Handle altitude
SubPxPosition = PPos.FromWPos(pos).ToPSubPos();
// Changes position, but not altitude
CenterPosition = cell.CenterPosition + new WVec(0, 0, CenterPosition.Z);
}
public void SetPosition(Actor self, WPos pos) { CenterPosition = pos; }
public void SetVisualPosition(Actor self, WPos pos) { SetPosition(self, pos); }
public bool AircraftCanEnter(Actor a)
{
if (self.AppearsHostileTo(a)) return false;
return Info.RearmBuildings.Contains(a.Info.Name)
|| Info.RepairBuildings.Contains(a.Info.Name);
if (self.AppearsHostileTo(a))
return false;
return info.RearmBuildings.Contains(a.Info.Name)
|| info.RepairBuildings.Contains(a.Info.Name);
}
public bool CanEnterCell(CPos location) { return true; }
@@ -125,20 +125,20 @@ namespace OpenRA.Mods.RA.Air
{
get
{
decimal ret = Info.Speed;
decimal ret = info.Speed;
foreach (var t in self.TraitsImplementing<ISpeedModifier>())
ret *= t.GetSpeedModifier();
return (int)ret;
}
}
Pair<CPos, SubCell>[] noCells = new Pair<CPos, SubCell>[] { };
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { return noCells; }
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { return NoCells; }
public void TickMove(int speed, int facing)
public WVec FlyStep(int facing)
{
var rawspeed = speed * 7 / (32 * PSubPos.PerPx);
SubPxPosition += rawspeed * -Util.SubPxVector[facing];
var speed = MovementSpeed * 7 * 1024 / (Game.CellSize * 32);
var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing));
return speed * dir / 1024;
}
public bool CanLand(CPos cell)
@@ -150,15 +150,15 @@ namespace OpenRA.Mods.RA.Air
return false;
var type = self.World.GetTerrainType(cell);
return Info.LandableTerrainTypes.Contains(type);
return info.LandableTerrainTypes.Contains(type);
}
public 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);
}
@@ -228,6 +228,7 @@ namespace OpenRA.Mods.RA.Air
cursor = self.World.Map.IsInMap(location) ? "move" : "move-blocked";
return true;
}
public bool IsQueued { get; protected set; }
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -30,8 +30,7 @@ namespace OpenRA.Mods.RA.Air
protected override bool CanAttack(Actor self, Target target)
{
// dont fire while landed
return base.CanAttack(self, target)
&& self.Trait<Aircraft>().Altitude > 0;
return base.CanAttack(self, target) && self.CenterPosition.Z > 0;
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -19,6 +19,7 @@ namespace OpenRA.Mods.RA.Air
public readonly bool Spins = true;
public readonly bool Moves = false;
public readonly WRange Velocity = new WRange(43);
public object Create(ActorInitializer init) { return new FallsToEarth(init.self, this); }
}
@@ -47,7 +48,7 @@ namespace OpenRA.Mods.RA.Air
public override Activity Tick(Actor self)
{
var aircraft = self.Trait<Aircraft>();
if (aircraft.Altitude <= 0)
if (self.CenterPosition.Z <= 0)
{
if (info.Explosion != null)
Combat.DoExplosion(self, info.Explosion, self.CenterPosition);
@@ -62,10 +63,9 @@ namespace OpenRA.Mods.RA.Air
aircraft.Facing = (aircraft.Facing + spin) % 256;
}
if (info.Moves)
FlyUtil.Fly(self, aircraft.Altitude);
aircraft.Altitude--;
var move = info.Moves ? aircraft.FlyStep(aircraft.Facing) : WVec.Zero;
move -= new WVec(WRange.Zero, WRange.Zero, info.Velocity);
aircraft.SetPosition(self, aircraft.CenterPosition + move);
return this;
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -20,6 +20,23 @@ namespace OpenRA.Mods.RA.Air
Fly(WPos pos) { this.pos = pos; }
public static void FlyToward(Actor self, Plane plane, int desiredFacing, WRange desiredAltitude)
{
var move = plane.FlyStep(plane.Facing);
var altitude = plane.CenterPosition.Z;
plane.Facing = Util.TickFacing(plane.Facing, desiredFacing, plane.ROT);
if (altitude != desiredAltitude.Range)
{
var delta = move.HorizontalLength * plane.Info.MaximumPitch.Tan() / 1024;
var dz = (desiredAltitude.Range - altitude).Clamp(-delta, delta);
move += new WVec(0, 0, dz);
}
plane.SetPosition(self, plane.CenterPosition + move);
}
public static Fly ToPos(WPos pos) { return new Fly(pos); }
public static Fly ToCell(CPos pos) { return new Fly(pos.CenterPosition); }
@@ -33,16 +50,16 @@ namespace OpenRA.Mods.RA.Air
if (d.HorizontalLengthSquared < 91022)
return NextActivity;
var aircraft = self.Trait<Aircraft>();
var cruiseAltitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude;
var desiredFacing = Util.GetFacing(d, aircraft.Facing);
if (aircraft.Altitude == cruiseAltitude)
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT);
var plane = self.Trait<Plane>();
var desiredFacing = Util.GetFacing(d, plane.Facing);
var cruiseAltitude = new WRange(plane.Info.CruiseAltitude * 1024 / Game.CellSize);
if (aircraft.Altitude < cruiseAltitude)
++aircraft.Altitude;
// Don't turn until we've reached the cruise altitude
if (plane.CenterPosition.Z < cruiseAltitude.Range)
desiredFacing = plane.Facing;
FlyToward(self, plane, desiredFacing, cruiseAltitude);
FlyUtil.Fly(self, cruiseAltitude);
return this;
}
@@ -51,14 +68,4 @@ namespace OpenRA.Mods.RA.Air
yield return Target.FromPos(pos);
}
}
public static class FlyUtil
{
public static void Fly(Actor self, int desiredAltitude)
{
var aircraft = self.Trait<Aircraft>();
aircraft.TickMove(PSubPos.PerPx * aircraft.MovementSpeed, aircraft.Facing);
aircraft.Altitude += Math.Sign(desiredAltitude - aircraft.Altitude);
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -17,20 +17,16 @@ namespace OpenRA.Mods.RA.Air
{
public override Activity Tick(Actor self)
{
var cruiseAltitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude;
if (IsCanceled)
return NextActivity;
if (IsCanceled) return NextActivity;
var plane = self.Trait<Plane>();
var aircraft = self.Trait<Aircraft>();
// We can't possibly turn this fast
var desiredFacing = plane.Facing + 64;
var cruiseAltitude = new WRange(plane.Info.CruiseAltitude * 1024 / Game.CellSize);
Fly.FlyToward(self, plane, desiredFacing, cruiseAltitude);
var desiredFacing = aircraft.Facing + 64; // we can't possibly turn this fast.
if (aircraft.Altitude == cruiseAltitude)
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT);
if (aircraft.Altitude < cruiseAltitude)
++aircraft.Altitude;
FlyUtil.Fly(self, cruiseAltitude);
return this;
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -20,10 +20,13 @@ namespace OpenRA.Mods.RA.Air
public override Activity Tick(Actor self)
{
if( IsCanceled ) return NextActivity;
var targetAltitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude;
if (remainingTicks-- == 0) return NextActivity;
FlyUtil.Fly(self, targetAltitude);
if (IsCanceled || remainingTicks-- == 0)
return NextActivity;
var plane = self.Trait<Plane>();
var cruiseAltitude = new WRange(plane.Info.CruiseAltitude * 1024 / Game.CellSize);
Fly.FlyToward(self, plane, plane.Facing, cruiseAltitude);
return this;
}
}
@@ -32,11 +35,12 @@ namespace OpenRA.Mods.RA.Air
{
public override Activity Tick(Actor self)
{
var targetAltitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude;
if (IsCanceled || !self.World.Map.IsInMap(self.Location))
return NextActivity;
FlyUtil.Fly(self, targetAltitude);
var plane = self.Trait<Plane>();
var cruiseAltitude = new WRange(plane.Info.CruiseAltitude * 1024 / Game.CellSize);
Fly.FlyToward(self, plane, plane.Facing, cruiseAltitude);
return this;
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -21,30 +21,29 @@ namespace OpenRA.Mods.RA.Air
public override Activity Tick(Actor self)
{
if (IsCanceled) return NextActivity;
if (!target.IsValid) return NextActivity;
if (IsCanceled || !target.IsValid)
return NextActivity;
var limitedAmmo = self.TraitOrDefault<LimitedAmmo>();
var reloads = self.TraitOrDefault<Reloads>();
if (limitedAmmo != null && !limitedAmmo.HasAmmo() && reloads == null)
return Util.SequenceActivities(new HeliReturn(), NextActivity);
var aircraft = self.Trait<Aircraft>();
var info = self.Info.Traits.Get<HelicopterInfo>();
if (aircraft.Altitude != info.CruiseAltitude)
{
aircraft.Altitude += Math.Sign(info.CruiseAltitude - aircraft.Altitude);
return this;
}
var helicopter = self.Trait<Helicopter>();
var attack = self.Trait<AttackHeli>();
var dist = target.CenterPosition - self.CenterPosition;
var desiredFacing = Util.GetFacing(dist, aircraft.Facing);
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT);
// Can rotate facing while ascending
var desiredFacing = Util.GetFacing(dist, helicopter.Facing);
helicopter.Facing = Util.TickFacing(helicopter.Facing, desiredFacing, helicopter.ROT);
var cruiseAltitude = new WRange(helicopter.Info.CruiseAltitude * 1024 / Game.CellSize);
if (HeliFly.AdjustAltitude(self, helicopter, cruiseAltitude))
return this;
// Fly towards the target
if (!target.IsInRange(self.CenterPosition, attack.GetMaximumRange()))
aircraft.TickMove(PSubPos.PerPx * aircraft.MovementSpeed, desiredFacing);
helicopter.SetPosition(self, helicopter.CenterPosition + helicopter.FlyStep(desiredFacing));
attack.DoAttack(self, target);

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -17,35 +17,48 @@ namespace OpenRA.Mods.RA.Air
class HeliFly : Activity
{
readonly WPos pos;
public HeliFly(WPos pos) { this.pos = pos; }
public HeliFly(CPos pos) { this.pos = pos.CenterPosition; }
public static bool AdjustAltitude(Actor self, Helicopter helicopter, WRange targetAltitude)
{
var altitude = helicopter.CenterPosition.Z;
if (altitude == targetAltitude.Range)
return false;
var delta = helicopter.Info.AltitudeVelocity.Range;
var dz = (targetAltitude.Range - altitude).Clamp(-delta, delta);
helicopter.SetPosition(self, helicopter.CenterPosition + new WVec(0, 0, dz));
return true;
}
public override Activity Tick(Actor self)
{
if (IsCanceled)
return NextActivity;
var info = self.Info.Traits.Get<HelicopterInfo>();
var aircraft = self.Trait<Aircraft>();
var helicopter = self.Trait<Helicopter>();
if (aircraft.Altitude != info.CruiseAltitude)
{
aircraft.Altitude += Math.Sign(info.CruiseAltitude - aircraft.Altitude);
var cruiseAltitude = new WRange(helicopter.Info.CruiseAltitude * 1024 / Game.CellSize);
if (HeliFly.AdjustAltitude(self, helicopter, cruiseAltitude))
return this;
}
// Rotate towards the target
var dist = pos - self.CenterPosition;
var desiredFacing = Util.GetFacing(dist, helicopter.Facing);
helicopter.Facing = Util.TickFacing(helicopter.Facing, desiredFacing, helicopter.ROT);
// The next move would overshoot, so just set the final position
var dist = pos - self.CenterPosition;
var moveDist = aircraft.MovementSpeed * 7 * 1024 / (Game.CellSize * 32);
if (dist.HorizontalLengthSquared < moveDist*moveDist)
var move = helicopter.FlyStep(desiredFacing);
if (dist.HorizontalLengthSquared < move.HorizontalLengthSquared)
{
aircraft.SetPosition(self, pos);
helicopter.SetPosition(self, pos + new WVec(0, 0, cruiseAltitude.Range - pos.Z));
return NextActivity;
}
var desiredFacing = Util.GetFacing(dist, aircraft.Facing);
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT);
aircraft.TickMove(PSubPos.PerPx * aircraft.MovementSpeed, desiredFacing);
helicopter.SetPosition(self, helicopter.CenterPosition + move);
return this;
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -14,27 +14,27 @@ namespace OpenRA.Mods.RA.Air
{
class HeliLand : Activity
{
public HeliLand(bool requireSpace, int minimalAltitude)
bool requireSpace;
public HeliLand(bool requireSpace)
{
this.requireSpace = requireSpace;
this.minimalAltitude = minimalAltitude;
}
bool requireSpace;
int minimalAltitude = 0;
public override Activity Tick(Actor self)
{
if (IsCanceled) return NextActivity;
var aircraft = self.Trait<Aircraft>();
if (aircraft.Altitude == minimalAltitude)
if (IsCanceled)
return NextActivity;
if (requireSpace && !aircraft.CanLand(self.Location))
var helicopter = self.Trait<Helicopter>();
if (requireSpace && !helicopter.CanLand(self.Location))
return this;
--aircraft.Altitude;
if (HeliFly.AdjustAltitude(self, helicopter, helicopter.Info.LandAltitude))
return this;
return NextActivity;
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -9,8 +9,8 @@
#endregion
using System.Linq;
using OpenRA.Traits;
using OpenRA.Mods.RA.Activities;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Air
{
@@ -20,15 +20,15 @@ namespace OpenRA.Mods.RA.Air
{
var rearmBuildings = self.Info.Traits.Get<HelicopterInfo>().RearmBuildings;
return self.World.Actors.Where(a => a.Owner == self.Owner).FirstOrDefault(
a => rearmBuildings.Contains(a.Info.Name) &&
!Reservable.IsReserved(a));
a => rearmBuildings.Contains(a.Info.Name) && !Reservable.IsReserved(a));
}
public override Activity Tick(Actor self)
{
if (IsCanceled) return NextActivity;
var dest = ChooseHelipad(self);
if (IsCanceled)
return NextActivity;
var dest = ChooseHelipad(self);
var initialFacing = self.Info.Traits.Get<AircraftInfo>().InitialFacing;
if (dest == null)
@@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA.Air
.ClosestTo(self);
if (nearestHpad == null)
return Util.SequenceActivities(new Turn(initialFacing), new HeliLand(true, 0), NextActivity);
return Util.SequenceActivities(new Turn(initialFacing), new HeliLand(true), NextActivity);
else
return Util.SequenceActivities(new HeliFly(nearestHpad.CenterPosition));
}
@@ -48,7 +48,7 @@ namespace OpenRA.Mods.RA.Air
var res = dest.TraitOrDefault<Reservable>();
var heli = self.Trait<Helicopter>();
if (res != null)
heli.reservation = res.Reserve(dest, self, heli);
heli.Reservation = res.Reserve(dest, self, heli);
var exit = dest.Info.Traits.WithInterface<ExitInfo>().FirstOrDefault();
var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero;
@@ -56,7 +56,7 @@ namespace OpenRA.Mods.RA.Air
return Util.SequenceActivities(
new HeliFly(dest.CenterPosition + offset),
new Turn(initialFacing),
new HeliLand(false, 0),
new HeliLand(false),
new Rearm(self),
NextActivity);
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -19,28 +19,29 @@ namespace OpenRA.Mods.RA.Air
{
public readonly WRange IdealSeparation = new WRange(1706);
public readonly bool LandWhenIdle = true;
public readonly int MinimalLandAltitude = 0;
public readonly WRange LandAltitude = WRange.Zero;
public readonly WRange AltitudeVelocity = new WRange(43);
public override object Create(ActorInitializer init) { return new Helicopter(init, this); }
}
class Helicopter : Aircraft, ITick, IResolveOrder
{
HelicopterInfo info;
public HelicopterInfo Info;
bool firstTick = true;
public Helicopter(ActorInitializer init, HelicopterInfo info)
: base(init, info)
{
this.info = info;
Info = info;
}
public void ResolveOrder(Actor self, Order order)
{
if (reservation != null)
if (Reservation != null)
{
reservation.Dispose();
reservation = null;
Reservation.Dispose();
Reservation = null;
}
if (order.OrderString == "Move")
@@ -51,10 +52,10 @@ namespace OpenRA.Mods.RA.Air
self.CancelActivity();
self.QueueActivity(new HeliFly(target));
if (info.LandWhenIdle)
if (Info.LandWhenIdle)
{
self.QueueActivity(new Turn(info.InitialFacing));
self.QueueActivity(new HeliLand(true, info.MinimalLandAltitude));
self.QueueActivity(new Turn(Info.InitialFacing));
self.QueueActivity(new HeliLand(true));
}
}
@@ -69,7 +70,7 @@ namespace OpenRA.Mods.RA.Air
{
var res = order.TargetActor.TraitOrDefault<Reservable>();
if (res != null)
reservation = res.Reserve(order.TargetActor, self, this);
Reservation = res.Reserve(order.TargetActor, self, this);
var exit = order.TargetActor.Info.Traits.WithInterface<ExitInfo>().FirstOrDefault();
var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero;
@@ -78,8 +79,8 @@ namespace OpenRA.Mods.RA.Air
self.CancelActivity();
self.QueueActivity(new HeliFly(order.TargetActor.CenterPosition + offset));
self.QueueActivity(new Turn(info.InitialFacing));
self.QueueActivity(new HeliLand(false, info.MinimalLandAltitude));
self.QueueActivity(new Turn(Info.InitialFacing));
self.QueueActivity(new HeliLand(false));
self.QueueActivity(new ResupplyAircraft());
}
}
@@ -94,10 +95,10 @@ namespace OpenRA.Mods.RA.Air
{
self.CancelActivity();
if (info.LandWhenIdle)
if (Info.LandWhenIdle)
{
self.QueueActivity(new Turn(info.InitialFacing));
self.QueueActivity(new HeliLand(true, info.MinimalLandAltitude));
self.QueueActivity(new Turn(Info.InitialFacing));
self.QueueActivity(new HeliLand(true));
}
}
}
@@ -112,10 +113,12 @@ namespace OpenRA.Mods.RA.Air
}
// Repulsion only applies when we're flying!
if (Altitude != info.CruiseAltitude)
var altitude = CenterPosition.Z;
var cruiseAltitude = Info.CruiseAltitude * 1024 / Game.CellSize;
if (altitude != cruiseAltitude)
return;
var otherHelis = self.World.FindActorsInCircle(self.CenterPosition, info.IdealSeparation)
var otherHelis = self.World.FindActorsInCircle(self.CenterPosition, Info.IdealSeparation)
.Where(a => a.HasTrait<Helicopter>());
var f = otherHelis
@@ -124,17 +127,17 @@ namespace OpenRA.Mods.RA.Air
int repulsionFacing = Util.GetFacing(f, -1);
if (repulsionFacing != -1)
TickMove(PSubPos.PerPx * MovementSpeed, repulsionFacing);
SetPosition(self, CenterPosition + FlyStep(repulsionFacing));
}
public WVec GetRepulseForce(Actor self, Actor other)
{
if (self == other || other.Trait<Helicopter>().Altitude < Altitude)
if (self == other || other.CenterPosition.Z < self.CenterPosition.Z)
return WVec.Zero;
var d = self.CenterPosition - other.CenterPosition;
var distSq = d.HorizontalLengthSquared;
if (distSq > info.IdealSeparation.Range * info.IdealSeparation.Range)
if (distSq > Info.IdealSeparation.Range * Info.IdealSeparation.Range)
return WVec.Zero;
if (distSq < 1)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -16,35 +16,31 @@ namespace OpenRA.Mods.RA.Air
{
public class Land : Activity
{
Target Target;
Target target;
public Land(Target t) { Target = t; }
public Land(Target t) { target = t; }
public override Activity Tick(Actor self)
{
if (!Target.IsValid)
if (!target.IsValid)
Cancel(self);
if (IsCanceled)
return NextActivity;
var aircraft = self.Trait<Aircraft>();
var d = Target.CenterPosition - self.CenterPosition;
var plane = self.Trait<Plane>();
var d = target.CenterPosition - self.CenterPosition;
// The next move would overshoot, so just set the final position
var moveDist = aircraft.MovementSpeed * 7 * 1024 / (Game.CellSize * 32);
if (d.HorizontalLengthSquared < moveDist*moveDist)
var move = plane.FlyStep(plane.Facing);
if (d.HorizontalLengthSquared < move.HorizontalLengthSquared)
{
aircraft.SetPosition(self, Target.CenterPosition);
plane.SetPosition(self, target.CenterPosition);
return NextActivity;
}
if (aircraft.Altitude > 0)
--aircraft.Altitude;
var desiredFacing = Util.GetFacing(d, aircraft.Facing);
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT);
aircraft.TickMove(PSubPos.PerPx * aircraft.MovementSpeed, aircraft.Facing);
var desiredFacing = Util.GetFacing(d, plane.Facing);
Fly.FlyToward(self, plane, desiredFacing, WRange.Zero);
return this;
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -16,15 +16,21 @@ namespace OpenRA.Mods.RA.Air
{
public class PlaneInfo : AircraftInfo
{
public readonly WAngle MaximumPitch = WAngle.FromDegrees(10);
public override object Create(ActorInitializer init) { return new Plane(init, this); }
}
public class Plane : Aircraft, IResolveOrder, ITick, ISync
{
public readonly PlaneInfo Info;
[Sync] public WPos RTBPathHash;
public Plane(ActorInitializer init, PlaneInfo info)
: base( init, info ) { }
: base(init, info)
{
Info = info;
}
bool firstTick = true;
public void Tick(Actor self)
@@ -49,7 +55,6 @@ namespace OpenRA.Mods.RA.Air
self.QueueActivity(Fly.ToCell(target));
self.QueueActivity(new FlyCircle());
}
else if (order.OrderString == "Enter")
{
if (Reservable.IsReserved(order.TargetActor)) return;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -17,14 +17,13 @@ namespace OpenRA.Mods.RA.Air
{
class ReturnOnIdleInfo : TraitInfo<ReturnOnIdle> { }
// fly home or fly-off-map behavior for idle planes
class ReturnOnIdle : INotifyIdle
{
public void TickIdle(Actor self)
{
var altitude = self.Trait<Aircraft>().Altitude;
if (altitude == 0) return; // we're on the ground, let's stay there.
// We're on the ground, let's stay there.
if (self.CenterPosition.Z == 0)
return;
var airfield = ReturnToBase.ChooseAirfield(self, true);
if (airfield != null)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -10,8 +10,8 @@
using System;
using System.Linq;
using OpenRA.Traits;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Air
{
@@ -46,22 +46,21 @@ namespace OpenRA.Mods.RA.Air
if (res != null)
{
plane.UnReserve();
plane.reservation = res.Reserve(dest, self, plane);
plane.Reservation = res.Reserve(dest, self, plane);
}
var landPos = dest.CenterPosition;
var speed = plane.MovementSpeed * 1024 / Game.CellSize / 5;
// Distance required for descent.
// TODO: Generalize this for arbitrary flight pitches
var landDistance = planeInfo.CruiseAltitude * speed;
var landDistance = planeInfo.CruiseAltitude * 1024 * 1024 / (Game.CellSize * plane.Info.MaximumPitch.Tan());
var altitude = planeInfo.CruiseAltitude * 1024 / Game.CellSize;
// Land towards the east
var approachStart = landPos + new WVec(-landDistance, 0, altitude);
// Add 10% to the turning radius to ensure we have enough room
var turnRadius = (int)(141 * speed / planeInfo.ROT / (float)(Math.PI));
var speed = plane.MovementSpeed * 1024 / (Game.CellSize * 5);
var turnRadius = (int)(141 * speed / planeInfo.ROT / (float)Math.PI);
// Find the center of the turning circles for clockwise and counterclockwise turns
var angle = WAngle.FromFacing(plane.Facing);

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -9,13 +9,13 @@
#endregion
using System.Drawing;
using OpenRA.Graphics;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Air
{
public class TargetableAircraftInfo : TargetableUnitInfo, Requires<AircraftInfo>
public class TargetableAircraftInfo : TargetableUnitInfo
{
public readonly string[] GroundedTargetTypes = { };
public override object Create(ActorInitializer init) { return new TargetableAircraft(init.self, this); }
@@ -24,18 +24,18 @@ namespace OpenRA.Mods.RA.Air
public class TargetableAircraft : TargetableUnit
{
readonly TargetableAircraftInfo info;
readonly Aircraft Aircraft;
readonly Actor self;
public TargetableAircraft(Actor self, TargetableAircraftInfo info)
: base(self, info)
{
this.info = info;
Aircraft = self.Trait<Aircraft>();
this.self = self;
}
public override string[] TargetTypes
{
get { return (Aircraft.Altitude > 0) ? info.TargetTypes
get { return (self.CenterPosition.Z > 0) ? info.TargetTypes
: info.GroundedTargetTypes; }
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2013 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,
@@ -52,7 +52,7 @@ namespace OpenRA.Mods.RA
var aircraft = self.TraitOrDefault<Aircraft>();
if (aircraft != null)
td.Add(new AltitudeInit(aircraft.Altitude));
td.Add(new AltitudeInit(aircraft.CenterPosition.Z * Game.CellSize / 1024));
var facing = self.TraitOrDefault<IFacing>();
if (facing != null)

View File

@@ -215,9 +215,10 @@ namespace OpenRA.Mods.RA.Missions
foreach (var aircraft in SovietAircraft())
{
var pos = aircraft.CenterPosition;
var plane = aircraft.Trait<Plane>();
var ammo = aircraft.Trait<LimitedAmmo>();
if ((plane.Altitude == 0 && ammo.FullAmmo()) || (plane.Altitude != 0 && ammo.HasAmmo()))
if ((pos.Z == 0 && ammo.FullAmmo()) || (pos.Z != 0 && ammo.HasAmmo()))
{
var enemy = FirstUnshroudedOrDefault(enemies.OrderBy(u => (aircraft.CenterPosition - u.CenterPosition).LengthSquared), world, 10);
if (enemy != null)
@@ -225,13 +226,13 @@ namespace OpenRA.Mods.RA.Missions
if (!aircraft.IsIdle && aircraft.GetCurrentActivity().GetType() != typeof(FlyAttack))
aircraft.CancelActivity();
if (plane.Altitude == 0)
if (pos.Z == 0)
plane.UnReserve();
aircraft.QueueActivity(new FlyAttack(Target.FromActor(enemy)));
}
}
else if (plane.Altitude != 0 && !LandIsQueued(aircraft))
else if (pos.Z != 0 && !LandIsQueued(aircraft))
{
aircraft.CancelActivity();
aircraft.QueueActivity(new ReturnToBase(aircraft, null));

View File

@@ -221,7 +221,7 @@ namespace OpenRA.Mods.RA.Missions
chinook.QueueActivity(new HeliFly(lz.CenterPosition + offset)); // no reservation of hpad but it's not needed
chinook.QueueActivity(new Turn(0));
chinook.QueueActivity(new HeliLand(false, 0));
chinook.QueueActivity(new HeliLand(false));
chinook.QueueActivity(new UnloadCargo(true));
chinook.QueueActivity(new Wait(150));
chinook.QueueActivity(new HeliFly(entry));

View File

@@ -47,7 +47,7 @@ namespace OpenRA.Mods.RA.Missions
var chinook = world.CreateActor("tran", new TypeDictionary { new OwnerInit(owner), new LocationInit(entry) });
chinook.QueueActivity(new HeliFly(lz));
chinook.QueueActivity(new Turn(0));
chinook.QueueActivity(new HeliLand(true, 0));
chinook.QueueActivity(new HeliLand(true));
chinook.QueueActivity(new WaitFor(() => chinook.Trait<Cargo>().Passengers.Contains(unit)));
chinook.QueueActivity(new Wait(150));
chinook.QueueActivity(new HeliFly(exit));
@@ -62,7 +62,7 @@ namespace OpenRA.Mods.RA.Missions
chinook.Trait<Cargo>().Load(chinook, unit);
chinook.QueueActivity(new HeliFly(lz));
chinook.QueueActivity(new Turn(0));
chinook.QueueActivity(new HeliLand(true, 0));
chinook.QueueActivity(new HeliLand(true));
chinook.QueueActivity(new UnloadCargo(true));
chinook.QueueActivity(new CallFunc(() => afterUnload(unit)));
chinook.QueueActivity(new Wait(150));

View File

@@ -19,7 +19,7 @@
LandableTerrainTypes: Sand, Rock, Transition, Spice, Dune
RepairBuildings: repair
RearmBuildings: starporta,starporto,starporth
MinimalLandAltitude: 25
LandAltitude: 800
RenderUnit:
WithCargo:
LocalOffset: 0,0,-854