#region Copyright & License Information /* * Copyright 2007-2011 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.Linq; using OpenRA.FileFormats; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Orders; using OpenRA.Traits; namespace OpenRA.Mods.RA.Air { public class DebugAircraftFacingInfo : ITraitInfo, Requires { public object Create(ActorInitializer init) { return new DebugAircraftFacing(init.self); } } public class DebugAircraftFacing : ISync { readonly Aircraft a; public DebugAircraftFacing(Actor self){ a = self.Trait(); } [Sync] public int foo { get { return a.Facing; } } } public class DebugAircraftSubPxXInfo : ITraitInfo, Requires { public object Create(ActorInitializer init) { return new DebugAircraftSubPxX(init.self); } } public class DebugAircraftSubPxX : ISync { readonly Aircraft a; public DebugAircraftSubPxX(Actor self){ a = self.Trait(); } [Sync] public int foo { get { return a.SubPxPosition.Y; } } } public class DebugAircraftSubPxYInfo : ITraitInfo, Requires { public object Create(ActorInitializer init) { return new DebugAircraftSubPxY(init.self); } } public class DebugAircraftSubPxY : ISync { readonly Aircraft a; public DebugAircraftSubPxY(Actor self){ a = self.Trait(); } [Sync] public int foo { get { return a.SubPxPosition.Y; } } } public class DebugAircraftAltitudeInfo : ITraitInfo, Requires { public object Create(ActorInitializer init) { return new DebugAircraftAltitude(init.self); } } public class DebugAircraftAltitude : ISync { readonly Aircraft a; public DebugAircraftAltitude(Actor self){ a = self.Trait(); } [Sync] public int foo { get { return a.Altitude; } } } public class AircraftInfo : ITraitInfo, IFacingInfo, UsesInit, UsesInit, UsesInit { public readonly int CruiseAltitude = 30; [ActorReference] public readonly string[] RepairBuildings = { "fix" }; [ActorReference] public readonly string[] RearmBuildings = { "hpad", "afld" }; public readonly int InitialFacing = 128; public readonly int ROT = 255; public readonly int Speed = 1; public readonly string[] LandableTerrainTypes = { }; public virtual object Create( ActorInitializer init ) { return new Aircraft( init , this ); } } public class Aircraft : IMove, IFacing, IOccupySpace, ISync, INotifyKilled, IIssueOrder, IOrderVoice { public IDisposable reservation; public void UnReserve() { 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 Altitude { get; set; } [Sync] public PSubPos SubPxPosition; public PPos PxPosition { get { return SubPxPosition.ToPPos(); } } public CPos TopLeft { get { return PxPosition.ToCPos(); } } readonly AircraftInfo Info; public Aircraft( ActorInitializer init , AircraftInfo info) { this.self = init.self; if( init.Contains() ) this.SubPxPosition = Util.CenterOfCell( init.Get() ).ToPSubPos(); this.Facing = init.Contains() ? init.Get() : info.InitialFacing; this.Altitude = init.Contains() ? init.Get() : 0; Info = info; } public Actor GetActorBelow() { if (self.Trait().Altitude != 0) return null; // not on the ground. return self.World.FindUnits(self.CenterLocation, self.CenterLocation) .FirstOrDefault( a => a.HasTrait() ); } protected void ReserveSpawnBuilding() { /* not spawning in the air, so try to assoc. with our afld. this is a hack. */ var afld = GetActorBelow(); if (afld == null) return; var res = afld.Trait(); if (res != null) reservation = res.Reserve(afld, self, this); } public int ROT { get { return Info.ROT; } } public int InitialFacing { get { return Info.InitialFacing; } } public void SetPosition(Actor self, CPos cell) { SetPxPosition( self, Util.CenterOfCell( cell ) ); } public void SetPxPosition( Actor self, PPos px ) { SubPxPosition = px.ToPSubPos(); } public void AdjustPxPosition(Actor self, PPos px) { SetPxPosition(self, px); } 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 CanEnterCell(CPos location) { return true; } public int MovementSpeed { get { decimal ret = Info.Speed; foreach( var t in self.TraitsImplementing() ) ret *= t.GetSpeedModifier(); return (int)ret; } } Pair[] noCells = new Pair[] { }; public IEnumerable> OccupiedCells() { return noCells; } public void TickMove( int speed, int facing ) { var rawspeed = speed * 7 / (32 * PSubPos.PerPx); SubPxPosition += rawspeed * -Util.SubPxVector[facing]; } public bool CanLand(CPos cell) { if (!self.World.Map.IsInMap(cell)) return false; if (self.World.ActorMap.AnyUnitsAt(cell)) return false; var type = self.World.GetTerrainType(cell); return Info.LandableTerrainTypes.Contains(type); } public IEnumerable GetResupplyActivities(Actor a) { var name = a.Info.Name; if (Info.RearmBuildings.Contains(name)) yield return new Rearm(self); if (Info.RepairBuildings.Contains(name)) yield return new Repair(a); } public IEnumerable Orders { get { yield return new EnterOrderTargeter("Enter", 5, false, true, target => AircraftCanEnter(target), target => !Reservable.IsReserved(target)); yield return new AircraftMoveOrderTargeter(); } } public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) { if (order.OrderID == "Enter") return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; if (order.OrderID == "Move") return new Order(order.OrderID, self, queued) { TargetLocation = target.CenterLocation.ToCPos() }; return null; } public string VoicePhraseForOrder(Actor self, Order order) { switch( order.OrderString ) { case "Move": case "Enter": case "ReturnToBase": return "Move"; default: return null; } } } public class ResupplyAircraft : Activity { public override Activity Tick(Actor self) { var aircraft = self.Trait(); var host = aircraft.GetActorBelow(); if (host == null) return NextActivity; return Util.SequenceActivities( aircraft.GetResupplyActivities(host).Append(NextActivity).ToArray()); } } class AircraftMoveOrderTargeter : IOrderTargeter { public string OrderID { get { return "Move"; } } public int OrderPriority { get { return 4; } } public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceQueued, ref string cursor) { return false; } public bool CanTargetLocation(Actor self, CPos location, List actorsAtLocation, bool forceAttack, bool forceQueued, ref string cursor) { IsQueued = forceQueued; cursor = self.World.Map.IsInMap(location) ? "move" : "move-blocked"; return true; } public bool IsQueued { get; protected set; } } }