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 #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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -19,10 +19,10 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Air namespace OpenRA.Mods.RA.Air
{ {
public class AircraftInfo : ITraitInfo, IFacingInfo, IOccupySpaceInfo, UsesInit<AltitudeInit>, UsesInit<LocationInit>, UsesInit<FacingInit> public class AircraftInfo : ITraitInfo, IFacingInfo, IOccupySpaceInfo, UsesInit<AltitudeInit>, UsesInit<LocationInit>, UsesInit<FacingInit>
{ {
public readonly int CruiseAltitude = 30; public readonly int CruiseAltitude = 30;
[ActorReference] [ActorReference]
public readonly string[] RepairBuildings = { "fix" }; public readonly string[] RepairBuildings = { "fix" };
[ActorReference] [ActorReference]
@@ -32,57 +32,47 @@ namespace OpenRA.Mods.RA.Air
public readonly int Speed = 1; public readonly int Speed = 1;
public readonly string[] LandableTerrainTypes = { }; public readonly string[] LandableTerrainTypes = { };
public virtual object Create( ActorInitializer init ) { return new Aircraft( init , this ); } public virtual object Create(ActorInitializer init) { return new Aircraft(init, this); }
public int GetInitialFacing() { return InitialFacing; } public int GetInitialFacing() { return InitialFacing; }
} }
public class Aircraft : IFacing, IPositionable, ISync, INotifyKilled, IIssueOrder, IOrderVoice 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() readonly AircraftInfo info;
{ readonly Actor self;
if (reservation != null)
{
reservation.Dispose();
reservation = null;
}
}
public void Killed(Actor self, AttackInfo e)
{
UnReserve();
}
protected readonly Actor self;
[Sync] public int Facing { get; set; } [Sync] public int Facing { get; set; }
[Sync] public int Altitude { get; set; } [Sync] public WPos CenterPosition { get; private set; }
[Sync] public PSubPos SubPxPosition; public CPos TopLeft { get { return CenterPosition.ToCPos(); } }
public IDisposable Reservation;
public int ROT { get { return info.ROT; } }
public WPos CenterPosition { get { return PxPosition.ToWPos(Altitude); } } public Aircraft(ActorInitializer init, AircraftInfo info)
public PPos PxPosition { get { return SubPxPosition.ToPPos(); } }
public CPos TopLeft { get { return PxPosition.ToCPos(); } }
readonly AircraftInfo Info;
public Aircraft(ActorInitializer init , AircraftInfo info)
{ {
this.info = info;
this.self = init.self; this.self = init.self;
if( init.Contains<LocationInit>() )
this.SubPxPosition = Util.CenterOfCell( init.Get<LocationInit, CPos>() ).ToPSubPos();
this.Facing = init.Contains<FacingInit>() ? init.Get<FacingInit,int>() : info.InitialFacing; if (init.Contains<LocationInit>())
this.Altitude = init.Contains<AltitudeInit>() ? init.Get<AltitudeInit,int>() : 0; SetPosition(self, init.Get<LocationInit, CPos>());
Info = info;
this.Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing;
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() public Actor GetActorBelow()
{ {
if (Altitude != 0) if (self.CenterPosition.Z != 0)
return null; // not on the ground. return null; // not on the ground.
return self.World.FindActorsInBox(self.CenterPosition, self.CenterPosition) return self.World.FindActorsInBox(self.CenterPosition, self.CenterPosition)
.FirstOrDefault( a => a.HasTrait<Reservable>() ); .FirstOrDefault(a => a.HasTrait<Reservable>());
} }
protected void ReserveSpawnBuilding() protected void ReserveSpawnBuilding()
@@ -94,29 +84,39 @@ namespace OpenRA.Mods.RA.Air
var res = afld.Trait<Reservable>(); var res = afld.Trait<Reservable>();
if (res != null) 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) public void SetPosition(Actor self, CPos cell)
{ {
SubPxPosition = Util.CenterOfCell(cell).ToPSubPos(); // Changes position, but not altitude
} CenterPosition = cell.CenterPosition + new WVec(0, 0, CenterPosition.Z);
public void SetPosition(Actor self, WPos pos)
{
// TODO: Handle altitude
SubPxPosition = PPos.FromWPos(pos).ToPSubPos();
} }
public void SetPosition(Actor self, WPos pos) { CenterPosition = pos; }
public void SetVisualPosition(Actor self, WPos pos) { SetPosition(self, pos); } public void SetVisualPosition(Actor self, WPos pos) { SetPosition(self, pos); }
public bool AircraftCanEnter(Actor a) public bool AircraftCanEnter(Actor a)
{ {
if (self.AppearsHostileTo(a)) return false; if (self.AppearsHostileTo(a))
return Info.RearmBuildings.Contains(a.Info.Name) return false;
|| Info.RepairBuildings.Contains(a.Info.Name);
return info.RearmBuildings.Contains(a.Info.Name)
|| info.RepairBuildings.Contains(a.Info.Name);
} }
public bool CanEnterCell(CPos location) { return true; } public bool CanEnterCell(CPos location) { return true; }
@@ -125,20 +125,20 @@ namespace OpenRA.Mods.RA.Air
{ {
get get
{ {
decimal ret = Info.Speed; decimal ret = info.Speed;
foreach (var t in self.TraitsImplementing<ISpeedModifier>()) foreach (var t in self.TraitsImplementing<ISpeedModifier>())
ret *= t.GetSpeedModifier(); ret *= t.GetSpeedModifier();
return (int)ret; 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); var speed = MovementSpeed * 7 * 1024 / (Game.CellSize * 32);
SubPxPosition += rawspeed * -Util.SubPxVector[facing]; var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing));
return speed * dir / 1024;
} }
public bool CanLand(CPos cell) public bool CanLand(CPos cell)
@@ -150,15 +150,15 @@ namespace OpenRA.Mods.RA.Air
return false; return false;
var type = self.World.GetTerrainType(cell); var type = self.World.GetTerrainType(cell);
return Info.LandableTerrainTypes.Contains(type); return info.LandableTerrainTypes.Contains(type);
} }
public IEnumerable<Activity> GetResupplyActivities(Actor a) public IEnumerable<Activity> GetResupplyActivities(Actor a)
{ {
var name = a.Info.Name; var name = a.Info.Name;
if (Info.RearmBuildings.Contains(name)) if (info.RearmBuildings.Contains(name))
yield return new Rearm(self); yield return new Rearm(self);
if (Info.RepairBuildings.Contains(name)) if (info.RepairBuildings.Contains(name))
yield return new Repair(a); yield return new Repair(a);
} }
@@ -228,6 +228,7 @@ namespace OpenRA.Mods.RA.Air
cursor = self.World.Map.IsInMap(location) ? "move" : "move-blocked"; cursor = self.World.Map.IsInMap(location) ? "move" : "move-blocked";
return true; return true;
} }
public bool IsQueued { get; protected set; } public bool IsQueued { get; protected set; }
} }
} }

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -24,14 +24,13 @@ namespace OpenRA.Mods.RA.Air
public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove) public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove)
{ {
return new FlyAttack( newTarget ); return new FlyAttack(newTarget);
} }
protected override bool CanAttack(Actor self, Target target) protected override bool CanAttack(Actor self, Target target)
{ {
// dont fire while landed // dont fire while landed
return base.CanAttack(self, target) return base.CanAttack(self, target) && self.CenterPosition.Z > 0;
&& self.Trait<Aircraft>().Altitude > 0;
} }
} }
} }

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * 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 Spins = true;
public readonly bool Moves = false; public readonly bool Moves = false;
public readonly WRange Velocity = new WRange(43);
public object Create(ActorInitializer init) { return new FallsToEarth(init.self, this); } 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) public override Activity Tick(Actor self)
{ {
var aircraft = self.Trait<Aircraft>(); var aircraft = self.Trait<Aircraft>();
if (aircraft.Altitude <= 0) if (self.CenterPosition.Z <= 0)
{ {
if (info.Explosion != null) if (info.Explosion != null)
Combat.DoExplosion(self, info.Explosion, self.CenterPosition); Combat.DoExplosion(self, info.Explosion, self.CenterPosition);
@@ -62,15 +63,14 @@ namespace OpenRA.Mods.RA.Air
aircraft.Facing = (aircraft.Facing + spin) % 256; aircraft.Facing = (aircraft.Facing + spin) % 256;
} }
if (info.Moves) var move = info.Moves ? aircraft.FlyStep(aircraft.Facing) : WVec.Zero;
FlyUtil.Fly(self, aircraft.Altitude); move -= new WVec(WRange.Zero, WRange.Zero, info.Velocity);
aircraft.SetPosition(self, aircraft.CenterPosition + move);
aircraft.Altitude--;
return this; return this;
} }
// Cannot be cancelled // Cannot be cancelled
public override void Cancel( Actor self ) { } public override void Cancel(Actor self) { }
} }
} }

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * 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; } 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 ToPos(WPos pos) { return new Fly(pos); }
public static Fly ToCell(CPos pos) { return new Fly(pos.CenterPosition); } public static Fly ToCell(CPos pos) { return new Fly(pos.CenterPosition); }
@@ -33,16 +50,16 @@ namespace OpenRA.Mods.RA.Air
if (d.HorizontalLengthSquared < 91022) if (d.HorizontalLengthSquared < 91022)
return NextActivity; return NextActivity;
var aircraft = self.Trait<Aircraft>(); var plane = self.Trait<Plane>();
var cruiseAltitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude; var desiredFacing = Util.GetFacing(d, plane.Facing);
var desiredFacing = Util.GetFacing(d, aircraft.Facing); var cruiseAltitude = new WRange(plane.Info.CruiseAltitude * 1024 / Game.CellSize);
if (aircraft.Altitude == cruiseAltitude)
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT);
if (aircraft.Altitude < cruiseAltitude) // Don't turn until we've reached the cruise altitude
++aircraft.Altitude; if (plane.CenterPosition.Z < cruiseAltitude.Range)
desiredFacing = plane.Facing;
FlyToward(self, plane, desiredFacing, cruiseAltitude);
FlyUtil.Fly(self, cruiseAltitude);
return this; return this;
} }
@@ -51,14 +68,4 @@ namespace OpenRA.Mods.RA.Air
yield return Target.FromPos(pos); 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 #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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * 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) 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; return this;
} }
} }

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * 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) public override Activity Tick(Actor self)
{ {
if( IsCanceled ) return NextActivity; if (IsCanceled || remainingTicks-- == 0)
var targetAltitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude; return NextActivity;
if (remainingTicks-- == 0) 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; return this;
} }
} }
@@ -32,15 +35,16 @@ namespace OpenRA.Mods.RA.Air
{ {
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
var targetAltitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude;
if (IsCanceled || !self.World.Map.IsInMap(self.Location)) if (IsCanceled || !self.World.Map.IsInMap(self.Location))
return NextActivity; 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; return this;
} }
public override void Cancel( Actor self ) public override void Cancel(Actor self)
{ {
base.Cancel(self); base.Cancel(self);
} }

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -17,36 +17,35 @@ namespace OpenRA.Mods.RA.Air
public class HeliAttack : Activity public class HeliAttack : Activity
{ {
Target target; Target target;
public HeliAttack( Target target ) { this.target = target; } public HeliAttack(Target target) { this.target = target; }
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
if (IsCanceled) return NextActivity; if (IsCanceled || !target.IsValid)
if (!target.IsValid) return NextActivity; return NextActivity;
var limitedAmmo = self.TraitOrDefault<LimitedAmmo>(); var limitedAmmo = self.TraitOrDefault<LimitedAmmo>();
var reloads = self.TraitOrDefault<Reloads>(); var reloads = self.TraitOrDefault<Reloads>();
if (limitedAmmo != null && !limitedAmmo.HasAmmo() && reloads == null) if (limitedAmmo != null && !limitedAmmo.HasAmmo() && reloads == null)
return Util.SequenceActivities( new HeliReturn(), NextActivity ); 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 attack = self.Trait<AttackHeli>();
var dist = target.CenterPosition - self.CenterPosition; var dist = target.CenterPosition - self.CenterPosition;
var desiredFacing = Util.GetFacing(dist, aircraft.Facing); // Can rotate facing while ascending
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); 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())) 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 ); attack.DoAttack(self, target);
return this; return this;
} }

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -17,35 +17,48 @@ namespace OpenRA.Mods.RA.Air
class HeliFly : Activity class HeliFly : Activity
{ {
readonly WPos pos; readonly WPos pos;
public HeliFly(WPos pos) { this.pos = pos; } public HeliFly(WPos pos) { this.pos = pos; }
public HeliFly(CPos pos) { this.pos = pos.CenterPosition; } 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) public override Activity Tick(Actor self)
{ {
if (IsCanceled) if (IsCanceled)
return NextActivity; return NextActivity;
var info = self.Info.Traits.Get<HelicopterInfo>(); var helicopter = self.Trait<Helicopter>();
var aircraft = self.Trait<Aircraft>();
if (aircraft.Altitude != info.CruiseAltitude) var cruiseAltitude = new WRange(helicopter.Info.CruiseAltitude * 1024 / Game.CellSize);
{ if (HeliFly.AdjustAltitude(self, helicopter, cruiseAltitude))
aircraft.Altitude += Math.Sign(info.CruiseAltitude - aircraft.Altitude);
return this; 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 // The next move would overshoot, so just set the final position
var dist = pos - self.CenterPosition; var move = helicopter.FlyStep(desiredFacing);
var moveDist = aircraft.MovementSpeed * 7 * 1024 / (Game.CellSize * 32); if (dist.HorizontalLengthSquared < move.HorizontalLengthSquared)
if (dist.HorizontalLengthSquared < moveDist*moveDist)
{ {
aircraft.SetPosition(self, pos); helicopter.SetPosition(self, pos + new WVec(0, 0, cruiseAltitude.Range - pos.Z));
return NextActivity; return NextActivity;
} }
var desiredFacing = Util.GetFacing(dist, aircraft.Facing); helicopter.SetPosition(self, helicopter.CenterPosition + move);
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT);
aircraft.TickMove(PSubPos.PerPx * aircraft.MovementSpeed, desiredFacing);
return this; return this;
} }

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -14,27 +14,27 @@ namespace OpenRA.Mods.RA.Air
{ {
class HeliLand : Activity class HeliLand : Activity
{ {
public HeliLand(bool requireSpace, int minimalAltitude) bool requireSpace;
public HeliLand(bool requireSpace)
{ {
this.requireSpace = requireSpace; this.requireSpace = requireSpace;
this.minimalAltitude = minimalAltitude;
} }
bool requireSpace;
int minimalAltitude = 0;
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
if (IsCanceled) return NextActivity; if (IsCanceled)
var aircraft = self.Trait<Aircraft>();
if (aircraft.Altitude == minimalAltitude)
return NextActivity; return NextActivity;
if (requireSpace && !aircraft.CanLand(self.Location)) var helicopter = self.Trait<Helicopter>();
if (requireSpace && !helicopter.CanLand(self.Location))
return this; return this;
--aircraft.Altitude; if (HeliFly.AdjustAltitude(self, helicopter, helicopter.Info.LandAltitude))
return this; 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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -9,8 +9,8 @@
#endregion #endregion
using System.Linq; using System.Linq;
using OpenRA.Traits;
using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Activities;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Air namespace OpenRA.Mods.RA.Air
{ {
@@ -19,16 +19,16 @@ namespace OpenRA.Mods.RA.Air
static Actor ChooseHelipad(Actor self) static Actor ChooseHelipad(Actor self)
{ {
var rearmBuildings = self.Info.Traits.Get<HelicopterInfo>().RearmBuildings; var rearmBuildings = self.Info.Traits.Get<HelicopterInfo>().RearmBuildings;
return self.World.Actors.Where( a => a.Owner == self.Owner ).FirstOrDefault( return self.World.Actors.Where(a => a.Owner == self.Owner).FirstOrDefault(
a => rearmBuildings.Contains(a.Info.Name) && a => rearmBuildings.Contains(a.Info.Name) && !Reservable.IsReserved(a));
!Reservable.IsReserved(a));
} }
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
if (IsCanceled) return NextActivity; if (IsCanceled)
var dest = ChooseHelipad(self); return NextActivity;
var dest = ChooseHelipad(self);
var initialFacing = self.Info.Traits.Get<AircraftInfo>().InitialFacing; var initialFacing = self.Info.Traits.Get<AircraftInfo>().InitialFacing;
if (dest == null) if (dest == null)
@@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA.Air
.ClosestTo(self); .ClosestTo(self);
if (nearestHpad == null) 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 else
return Util.SequenceActivities(new HeliFly(nearestHpad.CenterPosition)); return Util.SequenceActivities(new HeliFly(nearestHpad.CenterPosition));
} }
@@ -48,7 +48,7 @@ namespace OpenRA.Mods.RA.Air
var res = dest.TraitOrDefault<Reservable>(); var res = dest.TraitOrDefault<Reservable>();
var heli = self.Trait<Helicopter>(); var heli = self.Trait<Helicopter>();
if (res != null) 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 exit = dest.Info.Traits.WithInterface<ExitInfo>().FirstOrDefault();
var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero; var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero;
@@ -56,7 +56,7 @@ namespace OpenRA.Mods.RA.Air
return Util.SequenceActivities( return Util.SequenceActivities(
new HeliFly(dest.CenterPosition + offset), new HeliFly(dest.CenterPosition + offset),
new Turn(initialFacing), new Turn(initialFacing),
new HeliLand(false, 0), new HeliLand(false),
new Rearm(self), new Rearm(self),
NextActivity); 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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * 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 WRange IdealSeparation = new WRange(1706);
public readonly bool LandWhenIdle = true; 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); } public override object Create(ActorInitializer init) { return new Helicopter(init, this); }
} }
class Helicopter : Aircraft, ITick, IResolveOrder class Helicopter : Aircraft, ITick, IResolveOrder
{ {
HelicopterInfo info; public HelicopterInfo Info;
bool firstTick = true; bool firstTick = true;
public Helicopter(ActorInitializer init, HelicopterInfo info) public Helicopter(ActorInitializer init, HelicopterInfo info)
: base(init, info) : base(init, info)
{ {
this.info = info; Info = info;
} }
public void ResolveOrder(Actor self, Order order) public void ResolveOrder(Actor self, Order order)
{ {
if (reservation != null) if (Reservation != null)
{ {
reservation.Dispose(); Reservation.Dispose();
reservation = null; Reservation = null;
} }
if (order.OrderString == "Move") if (order.OrderString == "Move")
@@ -51,10 +52,10 @@ namespace OpenRA.Mods.RA.Air
self.CancelActivity(); self.CancelActivity();
self.QueueActivity(new HeliFly(target)); self.QueueActivity(new HeliFly(target));
if (info.LandWhenIdle) if (Info.LandWhenIdle)
{ {
self.QueueActivity(new Turn(info.InitialFacing)); self.QueueActivity(new Turn(Info.InitialFacing));
self.QueueActivity(new HeliLand(true, info.MinimalLandAltitude)); self.QueueActivity(new HeliLand(true));
} }
} }
@@ -69,7 +70,7 @@ namespace OpenRA.Mods.RA.Air
{ {
var res = order.TargetActor.TraitOrDefault<Reservable>(); var res = order.TargetActor.TraitOrDefault<Reservable>();
if (res != null) 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 exit = order.TargetActor.Info.Traits.WithInterface<ExitInfo>().FirstOrDefault();
var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero; var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero;
@@ -78,8 +79,8 @@ namespace OpenRA.Mods.RA.Air
self.CancelActivity(); self.CancelActivity();
self.QueueActivity(new HeliFly(order.TargetActor.CenterPosition + offset)); self.QueueActivity(new HeliFly(order.TargetActor.CenterPosition + offset));
self.QueueActivity(new Turn(info.InitialFacing)); self.QueueActivity(new Turn(Info.InitialFacing));
self.QueueActivity(new HeliLand(false, info.MinimalLandAltitude)); self.QueueActivity(new HeliLand(false));
self.QueueActivity(new ResupplyAircraft()); self.QueueActivity(new ResupplyAircraft());
} }
} }
@@ -94,10 +95,10 @@ namespace OpenRA.Mods.RA.Air
{ {
self.CancelActivity(); self.CancelActivity();
if (info.LandWhenIdle) if (Info.LandWhenIdle)
{ {
self.QueueActivity(new Turn(info.InitialFacing)); self.QueueActivity(new Turn(Info.InitialFacing));
self.QueueActivity(new HeliLand(true, info.MinimalLandAltitude)); self.QueueActivity(new HeliLand(true));
} }
} }
} }
@@ -112,10 +113,12 @@ namespace OpenRA.Mods.RA.Air
} }
// Repulsion only applies when we're flying! // 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; return;
var otherHelis = self.World.FindActorsInCircle(self.CenterPosition, info.IdealSeparation) var otherHelis = self.World.FindActorsInCircle(self.CenterPosition, Info.IdealSeparation)
.Where(a => a.HasTrait<Helicopter>()); .Where(a => a.HasTrait<Helicopter>());
var f = otherHelis var f = otherHelis
@@ -124,17 +127,17 @@ namespace OpenRA.Mods.RA.Air
int repulsionFacing = Util.GetFacing(f, -1); int repulsionFacing = Util.GetFacing(f, -1);
if (repulsionFacing != -1) if (repulsionFacing != -1)
TickMove(PSubPos.PerPx * MovementSpeed, repulsionFacing); SetPosition(self, CenterPosition + FlyStep(repulsionFacing));
} }
public WVec GetRepulseForce(Actor self, Actor other) 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; return WVec.Zero;
var d = self.CenterPosition - other.CenterPosition; var d = self.CenterPosition - other.CenterPosition;
var distSq = d.HorizontalLengthSquared; var distSq = d.HorizontalLengthSquared;
if (distSq > info.IdealSeparation.Range * info.IdealSeparation.Range) if (distSq > Info.IdealSeparation.Range * Info.IdealSeparation.Range)
return WVec.Zero; return WVec.Zero;
if (distSq < 1) if (distSq < 1)

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -16,35 +16,31 @@ namespace OpenRA.Mods.RA.Air
{ {
public class Land : Activity 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) public override Activity Tick(Actor self)
{ {
if (!Target.IsValid) if (!target.IsValid)
Cancel(self); Cancel(self);
if (IsCanceled) if (IsCanceled)
return NextActivity; return NextActivity;
var aircraft = self.Trait<Aircraft>(); var plane = self.Trait<Plane>();
var d = Target.CenterPosition - self.CenterPosition; var d = target.CenterPosition - self.CenterPosition;
// The next move would overshoot, so just set the final position // The next move would overshoot, so just set the final position
var moveDist = aircraft.MovementSpeed * 7 * 1024 / (Game.CellSize * 32); var move = plane.FlyStep(plane.Facing);
if (d.HorizontalLengthSquared < moveDist*moveDist) if (d.HorizontalLengthSquared < move.HorizontalLengthSquared)
{ {
aircraft.SetPosition(self, Target.CenterPosition); plane.SetPosition(self, target.CenterPosition);
return NextActivity; return NextActivity;
} }
if (aircraft.Altitude > 0) var desiredFacing = Util.GetFacing(d, plane.Facing);
--aircraft.Altitude; Fly.FlyToward(self, plane, desiredFacing, WRange.Zero);
var desiredFacing = Util.GetFacing(d, aircraft.Facing);
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT);
aircraft.TickMove(PSubPos.PerPx * aircraft.MovementSpeed, aircraft.Facing);
return this; return this;
} }

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -16,15 +16,21 @@ namespace OpenRA.Mods.RA.Air
{ {
public class PlaneInfo : AircraftInfo public class PlaneInfo : AircraftInfo
{ {
public override object Create( ActorInitializer init ) { return new Plane( init, this ); } 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 class Plane : Aircraft, IResolveOrder, ITick, ISync
{ {
public readonly PlaneInfo Info;
[Sync] public WPos RTBPathHash; [Sync] public WPos RTBPathHash;
public Plane( ActorInitializer init, PlaneInfo info ) public Plane(ActorInitializer init, PlaneInfo info)
: base( init, info ) { } : base(init, info)
{
Info = info;
}
bool firstTick = true; bool firstTick = true;
public void Tick(Actor self) public void Tick(Actor self)
@@ -49,7 +55,6 @@ namespace OpenRA.Mods.RA.Air
self.QueueActivity(Fly.ToCell(target)); self.QueueActivity(Fly.ToCell(target));
self.QueueActivity(new FlyCircle()); self.QueueActivity(new FlyCircle());
} }
else if (order.OrderString == "Enter") else if (order.OrderString == "Enter")
{ {
if (Reservable.IsReserved(order.TargetActor)) return; if (Reservable.IsReserved(order.TargetActor)) return;

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -17,14 +17,13 @@ namespace OpenRA.Mods.RA.Air
{ {
class ReturnOnIdleInfo : TraitInfo<ReturnOnIdle> { } class ReturnOnIdleInfo : TraitInfo<ReturnOnIdle> { }
// fly home or fly-off-map behavior for idle planes
class ReturnOnIdle : INotifyIdle class ReturnOnIdle : INotifyIdle
{ {
public void TickIdle(Actor self) public void TickIdle(Actor self)
{ {
var altitude = self.Trait<Aircraft>().Altitude; // We're on the ground, let's stay there.
if (altitude == 0) return; // we're on the ground, let's stay there. if (self.CenterPosition.Z == 0)
return;
var airfield = ReturnToBase.ChooseAirfield(self, true); var airfield = ReturnToBase.ChooseAirfield(self, true);
if (airfield != null) if (airfield != null)
@@ -38,13 +37,13 @@ namespace OpenRA.Mods.RA.Air
// i'd prefer something we own // i'd prefer something we own
var someBuilding = self.World.ActorsWithTrait<Building>() var someBuilding = self.World.ActorsWithTrait<Building>()
.Select( a => a.Actor ) .Select(a => a.Actor)
.FirstOrDefault(a => a.Owner == self.Owner); .FirstOrDefault(a => a.Owner == self.Owner);
// failing that, something unlikely to shoot at us // failing that, something unlikely to shoot at us
if (someBuilding == null) if (someBuilding == null)
someBuilding = self.World.ActorsWithTrait<Building>() someBuilding = self.World.ActorsWithTrait<Building>()
.Select( a => a.Actor ) .Select(a => a.Actor)
.FirstOrDefault(a => self.Owner.Stances[a.Owner] == Stance.Ally); .FirstOrDefault(a => self.Owner.Stances[a.Owner] == Stance.Ally);
if (someBuilding == null) if (someBuilding == null)

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -10,8 +10,8 @@
using System; using System;
using System.Linq; using System.Linq;
using OpenRA.Traits;
using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Buildings;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Air namespace OpenRA.Mods.RA.Air
{ {
@@ -46,22 +46,21 @@ namespace OpenRA.Mods.RA.Air
if (res != null) if (res != null)
{ {
plane.UnReserve(); plane.UnReserve();
plane.reservation = res.Reserve(dest, self, plane); plane.Reservation = res.Reserve(dest, self, plane);
} }
var landPos = dest.CenterPosition; var landPos = dest.CenterPosition;
var speed = plane.MovementSpeed * 1024 / Game.CellSize / 5;
// Distance required for descent. // Distance required for descent.
// TODO: Generalize this for arbitrary flight pitches var landDistance = planeInfo.CruiseAltitude * 1024 * 1024 / (Game.CellSize * plane.Info.MaximumPitch.Tan());
var landDistance = planeInfo.CruiseAltitude * speed;
var altitude = planeInfo.CruiseAltitude * 1024 / Game.CellSize; var altitude = planeInfo.CruiseAltitude * 1024 / Game.CellSize;
// Land towards the east // Land towards the east
var approachStart = landPos + new WVec(-landDistance, 0, altitude); var approachStart = landPos + new WVec(-landDistance, 0, altitude);
// Add 10% to the turning radius to ensure we have enough room // 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 // Find the center of the turning circles for clockwise and counterclockwise turns
var angle = WAngle.FromFacing(plane.Facing); var angle = WAngle.FromFacing(plane.Facing);

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -9,13 +9,13 @@
#endregion #endregion
using System.Drawing; using System.Drawing;
using OpenRA.Graphics;
using System.Linq; using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA.Air namespace OpenRA.Mods.RA.Air
{ {
public class TargetableAircraftInfo : TargetableUnitInfo, Requires<AircraftInfo> public class TargetableAircraftInfo : TargetableUnitInfo
{ {
public readonly string[] GroundedTargetTypes = { }; public readonly string[] GroundedTargetTypes = { };
public override object Create(ActorInitializer init) { return new TargetableAircraft(init.self, this); } public override object Create(ActorInitializer init) { return new TargetableAircraft(init.self, this); }
@@ -24,19 +24,19 @@ namespace OpenRA.Mods.RA.Air
public class TargetableAircraft : TargetableUnit public class TargetableAircraft : TargetableUnit
{ {
readonly TargetableAircraftInfo info; readonly TargetableAircraftInfo info;
readonly Aircraft Aircraft; readonly Actor self;
public TargetableAircraft(Actor self, TargetableAircraftInfo info) public TargetableAircraft(Actor self, TargetableAircraftInfo info)
: base(self, info) : base(self, info)
{ {
this.info = info; this.info = info;
Aircraft = self.Trait<Aircraft>(); this.self = self;
} }
public override string[] TargetTypes public override string[] TargetTypes
{ {
get { return (Aircraft.Altitude > 0) ? info.TargetTypes get { return (self.CenterPosition.Z > 0) ? info.TargetTypes
: info.GroundedTargetTypes; } : info.GroundedTargetTypes; }
} }
} }
} }

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 * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -52,7 +52,7 @@ namespace OpenRA.Mods.RA
var aircraft = self.TraitOrDefault<Aircraft>(); var aircraft = self.TraitOrDefault<Aircraft>();
if (aircraft != null) if (aircraft != null)
td.Add(new AltitudeInit(aircraft.Altitude)); td.Add(new AltitudeInit(aircraft.CenterPosition.Z * Game.CellSize / 1024));
var facing = self.TraitOrDefault<IFacing>(); var facing = self.TraitOrDefault<IFacing>();
if (facing != null) if (facing != null)

View File

@@ -215,9 +215,10 @@ namespace OpenRA.Mods.RA.Missions
foreach (var aircraft in SovietAircraft()) foreach (var aircraft in SovietAircraft())
{ {
var pos = aircraft.CenterPosition;
var plane = aircraft.Trait<Plane>(); var plane = aircraft.Trait<Plane>();
var ammo = aircraft.Trait<LimitedAmmo>(); 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); var enemy = FirstUnshroudedOrDefault(enemies.OrderBy(u => (aircraft.CenterPosition - u.CenterPosition).LengthSquared), world, 10);
if (enemy != null) if (enemy != null)
@@ -225,13 +226,13 @@ namespace OpenRA.Mods.RA.Missions
if (!aircraft.IsIdle && aircraft.GetCurrentActivity().GetType() != typeof(FlyAttack)) if (!aircraft.IsIdle && aircraft.GetCurrentActivity().GetType() != typeof(FlyAttack))
aircraft.CancelActivity(); aircraft.CancelActivity();
if (plane.Altitude == 0) if (pos.Z == 0)
plane.UnReserve(); plane.UnReserve();
aircraft.QueueActivity(new FlyAttack(Target.FromActor(enemy))); aircraft.QueueActivity(new FlyAttack(Target.FromActor(enemy)));
} }
} }
else if (plane.Altitude != 0 && !LandIsQueued(aircraft)) else if (pos.Z != 0 && !LandIsQueued(aircraft))
{ {
aircraft.CancelActivity(); aircraft.CancelActivity();
aircraft.QueueActivity(new ReturnToBase(aircraft, null)); 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 HeliFly(lz.CenterPosition + offset)); // no reservation of hpad but it's not needed
chinook.QueueActivity(new Turn(0)); chinook.QueueActivity(new Turn(0));
chinook.QueueActivity(new HeliLand(false, 0)); chinook.QueueActivity(new HeliLand(false));
chinook.QueueActivity(new UnloadCargo(true)); chinook.QueueActivity(new UnloadCargo(true));
chinook.QueueActivity(new Wait(150)); chinook.QueueActivity(new Wait(150));
chinook.QueueActivity(new HeliFly(entry)); 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) }); var chinook = world.CreateActor("tran", new TypeDictionary { new OwnerInit(owner), new LocationInit(entry) });
chinook.QueueActivity(new HeliFly(lz)); chinook.QueueActivity(new HeliFly(lz));
chinook.QueueActivity(new Turn(0)); 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 WaitFor(() => chinook.Trait<Cargo>().Passengers.Contains(unit)));
chinook.QueueActivity(new Wait(150)); chinook.QueueActivity(new Wait(150));
chinook.QueueActivity(new HeliFly(exit)); chinook.QueueActivity(new HeliFly(exit));
@@ -62,7 +62,7 @@ namespace OpenRA.Mods.RA.Missions
chinook.Trait<Cargo>().Load(chinook, unit); chinook.Trait<Cargo>().Load(chinook, unit);
chinook.QueueActivity(new HeliFly(lz)); chinook.QueueActivity(new HeliFly(lz));
chinook.QueueActivity(new Turn(0)); chinook.QueueActivity(new Turn(0));
chinook.QueueActivity(new HeliLand(true, 0)); chinook.QueueActivity(new HeliLand(true));
chinook.QueueActivity(new UnloadCargo(true)); chinook.QueueActivity(new UnloadCargo(true));
chinook.QueueActivity(new CallFunc(() => afterUnload(unit))); chinook.QueueActivity(new CallFunc(() => afterUnload(unit)));
chinook.QueueActivity(new Wait(150)); chinook.QueueActivity(new Wait(150));

View File

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