Merge pull request #3586 from pchote/omg-even-more-world-coords
Convert actor positioning to world coordinates.
This commit is contained in:
@@ -36,8 +36,10 @@ namespace OpenRA
|
||||
public static bool operator !=(WVec me, WVec other) { return !(me == other); }
|
||||
|
||||
public static int Dot(WVec a, WVec b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; }
|
||||
public int LengthSquared { get { return X * X + Y * Y + Z * Z; } }
|
||||
public long LengthSquared { get { return (long)X * X + (long)Y * Y + (long)Z * Z; } }
|
||||
public int Length { get { return (int)Math.Sqrt(LengthSquared); } }
|
||||
public long HorizontalLengthSquared { get { return (long)X * X + (long)Y * Y; } }
|
||||
public int HorizontalLength { get { return (int)Math.Sqrt(HorizontalLengthSquared); } }
|
||||
|
||||
public WVec Rotate(WRot rot)
|
||||
{
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace OpenRA
|
||||
public readonly uint ActorID;
|
||||
|
||||
Lazy<IOccupySpace> occupySpace;
|
||||
IHasLocation HasLocation;
|
||||
Lazy<IMove> Move;
|
||||
Lazy<IFacing> Facing;
|
||||
|
||||
public Cached<Rectangle> Bounds;
|
||||
@@ -36,25 +34,8 @@ namespace OpenRA
|
||||
public IOccupySpace OccupiesSpace { get { return occupySpace.Value; } }
|
||||
|
||||
public CPos Location { get { return occupySpace.Value.TopLeft; } }
|
||||
|
||||
public PPos CenterLocation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HasLocation == null)
|
||||
HasLocation = Trait<IHasLocation>();
|
||||
return HasLocation.PxPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public WPos CenterPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
var altitude = Move.Value != null ? Move.Value.Altitude : 0;
|
||||
return CenterLocation.ToWPos(altitude);
|
||||
}
|
||||
}
|
||||
public PPos CenterLocation { get { return PPos.FromWPos(occupySpace.Value.CenterPosition); } }
|
||||
public WPos CenterPosition { get { return occupySpace.Value.CenterPosition; } }
|
||||
|
||||
public WRot Orientation
|
||||
{
|
||||
@@ -93,7 +74,6 @@ namespace OpenRA
|
||||
AddTrait(trait.Create(init));
|
||||
}
|
||||
|
||||
Move = Lazy.New(() => TraitOrDefault<IMove>());
|
||||
Facing = Lazy.New(() => TraitOrDefault<IFacing>());
|
||||
|
||||
Size = Lazy.New(() =>
|
||||
@@ -152,13 +132,14 @@ namespace OpenRA
|
||||
loc += new PVecInt(si.Bounds[2], si.Bounds[3]);
|
||||
}
|
||||
|
||||
var move = Move.Value;
|
||||
if (move != null)
|
||||
var ios = occupySpace.Value;
|
||||
if (ios != null)
|
||||
{
|
||||
loc -= new PVecInt(0, move.Altitude);
|
||||
var altitude = ios.CenterPosition.Z * Game.CellSize / 1024;
|
||||
loc -= new PVecInt(0, altitude);
|
||||
|
||||
if (useAltitude)
|
||||
size = new PVecInt(size.X, size.Y + move.Altitude);
|
||||
size = new PVecInt(size.X, size.Y + altitude);
|
||||
}
|
||||
|
||||
return new Rectangle(loc.X, loc.Y, size.X, size.Y);
|
||||
|
||||
@@ -45,8 +45,7 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
public bool IsValid { get { return valid && (actor == null || (actor.IsInWorld && !actor.IsDead() && actor.Generation == generation)); } }
|
||||
public PPos PxPosition { get { return IsActor ? actor.Trait<IHasLocation>().PxPosition : PPos.FromWPos(pos); } }
|
||||
public PPos CenterLocation { get { return PxPosition; } }
|
||||
public PPos CenterLocation { get { return IsActor ? actor.CenterLocation : PPos.FromWPos(pos); } }
|
||||
public Actor Actor { get { return IsActor ? actor : null; } }
|
||||
|
||||
// TODO: This should return true even if the actor is destroyed
|
||||
@@ -91,12 +90,7 @@ namespace OpenRA.Traits
|
||||
|
||||
// Target ranges are calculated in 2D, so ignore height differences
|
||||
var rangeSquared = range.Range*range.Range;
|
||||
return Positions.Any(t =>
|
||||
{
|
||||
var dx = (long)(t.X - origin.X);
|
||||
var dy = (long)(t.Y - origin.Y);
|
||||
return dx*dx + dy*dy <= rangeSquared;
|
||||
});
|
||||
return Positions.Any(t => (t - origin).HorizontalLengthSquared <= rangeSquared);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -96,10 +96,11 @@ namespace OpenRA.Traits
|
||||
|
||||
public interface IVisibilityModifier { bool IsVisible(Actor self, Player byPlayer); }
|
||||
public interface IRadarColorModifier { Color RadarColorOverride(Actor self); }
|
||||
public interface IHasLocation { PPos PxPosition { get; } }
|
||||
|
||||
public interface IOccupySpace : IHasLocation
|
||||
public interface IOccupySpaceInfo { }
|
||||
public interface IOccupySpace
|
||||
{
|
||||
WPos CenterPosition { get; }
|
||||
CPos TopLeft { get; }
|
||||
IEnumerable<Pair<CPos, SubCell>> OccupiedCells();
|
||||
}
|
||||
@@ -134,15 +135,14 @@ namespace OpenRA.Traits
|
||||
public interface ITags { IEnumerable<TagType> GetTags(); }
|
||||
public interface ISelectionBar { float GetValue(); Color GetColor(); }
|
||||
|
||||
public interface ITeleportable : IHasLocation /* crap name! */
|
||||
public interface IPositionable : IOccupySpace
|
||||
{
|
||||
bool CanEnterCell(CPos location);
|
||||
void SetPosition(Actor self, CPos cell);
|
||||
void SetPxPosition(Actor self, PPos px);
|
||||
void AdjustPxPosition(Actor self, PPos px); /* works like SetPxPosition, but visual only */
|
||||
void SetPosition(Actor self, WPos pos);
|
||||
void SetVisualPosition(Actor self, WPos pos);
|
||||
}
|
||||
|
||||
public interface IMove : ITeleportable { int Altitude { get; set; } }
|
||||
public interface INotifyBlockingMove { void OnNotifyBlockingMove(Actor self, Actor blocking); }
|
||||
|
||||
public interface IFacing
|
||||
|
||||
@@ -100,9 +100,9 @@ namespace OpenRA.Traits
|
||||
return loc.ToPPos() + new PVecInt(Game.CellSize / 2, Game.CellSize / 2);
|
||||
}
|
||||
|
||||
public static PPos BetweenCells(CPos from, CPos to)
|
||||
public static WPos BetweenCells(CPos from, CPos to)
|
||||
{
|
||||
return PPos.Lerp(CenterOfCell(from), CenterOfCell(to), 1, 2);
|
||||
return WPos.Lerp(from.CenterPosition, to.CenterPosition, 1, 2);
|
||||
}
|
||||
|
||||
public static int2 AsInt2(this int[] xs) { return new int2(xs[0], xs[1]); }
|
||||
|
||||
@@ -13,7 +13,7 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class WaypointInfo : ITraitInfo
|
||||
class WaypointInfo : ITraitInfo, IOccupySpaceInfo
|
||||
{
|
||||
public object Create( ActorInitializer init ) { return new Waypoint( init ); }
|
||||
}
|
||||
@@ -28,8 +28,7 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
public CPos TopLeft { get { return location; } }
|
||||
|
||||
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { yield break; }
|
||||
public PPos PxPosition { get { return Util.CenterOfCell(location); } }
|
||||
public WPos CenterPosition { get { return location.CenterPosition; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace OpenRA.Traits
|
||||
for (var i = 0; i <= bins.GetUpperBound(0); i++)
|
||||
bins[i, j].Clear();
|
||||
|
||||
foreach (var a in self.World.ActorsWithTrait<IHasLocation>())
|
||||
foreach (var a in self.World.ActorsWithTrait<IOccupySpace>())
|
||||
{
|
||||
var bounds = a.Actor.ExtendedBounds.Value;
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace OpenRA.Mods.Cnc
|
||||
{
|
||||
public class HarvesterDockSequence : Activity
|
||||
{
|
||||
enum State { Wait, Turn, DragIn, Dock, Loop, Undock, DragOut };
|
||||
enum State { Wait, Turn, DragIn, Dock, Loop, Undock, DragOut }
|
||||
static readonly WVec DockOffset = new WVec(-640, 341, 0);
|
||||
|
||||
readonly Actor proc;
|
||||
readonly Harvester harv;
|
||||
@@ -34,8 +35,8 @@ namespace OpenRA.Mods.Cnc
|
||||
state = State.Turn;
|
||||
harv = self.Trait<Harvester>();
|
||||
ru = self.Trait<RenderUnit>();
|
||||
startDock = self.Trait<IHasLocation>().PxPosition.ToWPos(0);
|
||||
endDock = (proc.Trait<IHasLocation>().PxPosition + new PVecInt(-15,8)).ToWPos(0);
|
||||
startDock = self.CenterPosition;
|
||||
endDock = proc.CenterPosition + DockOffset;
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
@@ -51,7 +52,7 @@ namespace OpenRA.Mods.Cnc
|
||||
state = State.Dock;
|
||||
return Util.SequenceActivities(new Drag(startDock, endDock, 12), this);
|
||||
case State.Dock:
|
||||
ru.PlayCustomAnimation(self, "dock", () => {ru.PlayCustomAnimRepeating(self, "dock-loop"); state = State.Loop;});
|
||||
ru.PlayCustomAnimation(self, "dock", () => { ru.PlayCustomAnimRepeating(self, "dock-loop"); state = State.Loop; });
|
||||
state = State.Wait;
|
||||
return this;
|
||||
case State.Loop:
|
||||
@@ -65,6 +66,7 @@ namespace OpenRA.Mods.Cnc
|
||||
case State.DragOut:
|
||||
return Util.SequenceActivities(new Drag(endDock, startDock, 12), NextActivity);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Invalid harvester dock state");
|
||||
}
|
||||
|
||||
@@ -73,10 +75,9 @@ namespace OpenRA.Mods.Cnc
|
||||
state = State.Undock;
|
||||
}
|
||||
|
||||
public override IEnumerable<Target> GetTargets( Actor self )
|
||||
public override IEnumerable<Target> GetTargets(Actor self)
|
||||
{
|
||||
yield return Target.FromActor(proc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -205,7 +205,7 @@ namespace OpenRA.Mods.Cnc.Missions
|
||||
{
|
||||
if (b.Destroyed) return;
|
||||
w2.Add(b);
|
||||
b.TraitsImplementing<IMove>().FirstOrDefault().SetPosition(b, a.Location);
|
||||
b.TraitsImplementing<IPositionable>().FirstOrDefault().SetPosition(b, a.Location);
|
||||
b.QueueActivity(mobile.MoveTo(unload, 2));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,201 +1,201 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2012 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,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Cnc;
|
||||
using OpenRA.Mods.RA;
|
||||
using OpenRA.Mods.RA.Air;
|
||||
using OpenRA.Mods.RA.Move;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Mods.RA.Missions;
|
||||
using OpenRA.Mods.RA.Buildings;
|
||||
using OpenRA.Scripting;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Mods.Cnc.Missions
|
||||
{
|
||||
class Nod01ScriptInfo : TraitInfo<Nod01Script>, Requires<SpawnMapActorsInfo> { }
|
||||
|
||||
class Nod01Script : IHasObjectives, IWorldLoaded, ITick
|
||||
{
|
||||
public event Action<bool> OnObjectivesUpdated = notify => { };
|
||||
|
||||
public IEnumerable<Objective> Objectives { get { return new[] { killnikoomba, levelvillage }; } }
|
||||
|
||||
Objective killnikoomba = new Objective(ObjectiveType.Primary, KillNikoombaText, ObjectiveStatus.InProgress);
|
||||
Objective levelvillage = new Objective(ObjectiveType.Primary, LevelVillageText, ObjectiveStatus.Inactive);
|
||||
|
||||
const string KillNikoombaText = "Find Nikoomba. Once found he must be assasinated.";
|
||||
const string LevelVillageText = "Nikoomba has met his demise, now level the village.";
|
||||
|
||||
Player gdi;
|
||||
Player nod;
|
||||
|
||||
//actors and the likes go here
|
||||
Actor nikoomba;
|
||||
Actor vil01;
|
||||
Actor vil02;
|
||||
Actor vil03;
|
||||
Actor vil04;
|
||||
Actor vil05;
|
||||
Actor vil06;
|
||||
Actor vil07;
|
||||
Actor vil08;
|
||||
Actor vil09;
|
||||
Actor vil10;
|
||||
Actor vil11;
|
||||
Actor vil12;
|
||||
Actor vil13;
|
||||
Actor civ01;
|
||||
Actor civ02;
|
||||
Actor civ03;
|
||||
Actor civ04;
|
||||
Actor civ05;
|
||||
Actor civ06;
|
||||
Actor civ07;
|
||||
|
||||
//waypoints
|
||||
Actor nr1;
|
||||
Actor nr2;
|
||||
Actor gr1;
|
||||
|
||||
World world;
|
||||
|
||||
//in the allies01 script stuff was here not needed for me so far
|
||||
const string NRName = "E1";
|
||||
const string GRName = "E2";
|
||||
const string GRName2 = "JEEP";
|
||||
|
||||
void MissionFailed(string text)
|
||||
{
|
||||
MissionUtils.CoopMissionFailed(world, text, nod);
|
||||
}
|
||||
|
||||
void MissionAccomplished(string text)
|
||||
{
|
||||
MissionUtils.CoopMissionAccomplished(world, text, nod);
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (nod.WinState != WinState.Undefined) return;
|
||||
|
||||
//spawns nod reinf
|
||||
if (world.FrameNumber == 700)
|
||||
{
|
||||
NODReinforceNthA();
|
||||
Sound.Play("reinfor1.aud");
|
||||
}
|
||||
if (world.FrameNumber == 1400)
|
||||
{
|
||||
NODReinforceNthB();
|
||||
Sound.Play("reinfor1.aud");
|
||||
}
|
||||
// objectives
|
||||
if (killnikoomba.Status == ObjectiveStatus.InProgress)
|
||||
{
|
||||
if (nikoomba.Destroyed)
|
||||
{
|
||||
killnikoomba.Status = ObjectiveStatus.Completed;
|
||||
levelvillage.Status = ObjectiveStatus.InProgress;
|
||||
OnObjectivesUpdated(true);
|
||||
//DisplayObjective();
|
||||
//GDIReinforceNth();
|
||||
}
|
||||
}
|
||||
if (levelvillage.Status == ObjectiveStatus.InProgress)
|
||||
{
|
||||
if (vil01.Destroyed && vil02.Destroyed && vil03.Destroyed && vil04.Destroyed && vil05.Destroyed && vil06.Destroyed &&
|
||||
vil07.Destroyed && vil08.Destroyed && vil09.Destroyed && vil10.Destroyed && vil11.Destroyed && vil12.Destroyed &&
|
||||
vil13.Destroyed && civ01.Destroyed && civ02.Destroyed && civ03.Destroyed && civ04.Destroyed && civ05.Destroyed &&
|
||||
civ06.Destroyed && civ07.Destroyed)
|
||||
{
|
||||
levelvillage.Status = ObjectiveStatus.Completed;
|
||||
OnObjectivesUpdated(true);
|
||||
MissionAccomplished("Nikoomba was killed and the village was destroyed.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!world.Actors.Any(a => (a.Owner == nod) && a.IsInWorld && !a.IsDead()))
|
||||
{
|
||||
MissionFailed("The Nod forces in the area have been wiped out.");
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<Actor> UnitsNearActor(Actor actor, int range)
|
||||
{
|
||||
return world.FindActorsInCircle(actor.CenterPosition, WRange.FromCells(range))
|
||||
.Where(a => a.IsInWorld && a != world.WorldActor && !a.Destroyed && a.HasTrait<IMove>() && !a.Owner.NonCombatant);
|
||||
}
|
||||
|
||||
void NODReinforceNthA()
|
||||
{
|
||||
nr1 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr1.Location) });
|
||||
nr1 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr1.Location) });
|
||||
}
|
||||
|
||||
void NODReinforceNthB()
|
||||
{
|
||||
nr2 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr2.Location) });
|
||||
nr2 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr2.Location) });
|
||||
//nr1.QueueActivity(new Move.Move(nr1.Location - new CVec(0, 2)));
|
||||
}
|
||||
|
||||
void GDIReinforceNth()
|
||||
{
|
||||
gr1 = world.CreateActor(true, GRName, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) });
|
||||
gr1 = world.CreateActor(true, GRName, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) });
|
||||
gr1 = world.CreateActor(true, GRName2, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) });
|
||||
//gr1.QueueActivity(new Move.Move(nr1.Location - new CVec(0, 2)));
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w)
|
||||
{
|
||||
world = w;
|
||||
gdi = w.Players.Single(p => p.InternalName == "GDI");
|
||||
nod = w.Players.Single(p => p.InternalName == "NOD");
|
||||
var actors = w.WorldActor.Trait<SpawnMapActors>().Actors;
|
||||
nikoomba = actors["Nikoomba"];
|
||||
vil01 = actors["Vil01"];
|
||||
vil02 = actors["Vil02"];
|
||||
vil03 = actors["Vil03"];
|
||||
vil04 = actors["Vil04"];
|
||||
vil05 = actors["Vil05"];
|
||||
vil06 = actors["Vil06"];
|
||||
vil07 = actors["Vil07"];
|
||||
vil08 = actors["Vil08"];
|
||||
vil09 = actors["Vil09"];
|
||||
vil10 = actors["Vil10"];
|
||||
vil11 = actors["Vil11"];
|
||||
vil12 = actors["Vil12"];
|
||||
vil13 = actors["Vil13"];
|
||||
civ01 = actors["Civ01"];
|
||||
civ02 = actors["Civ02"];
|
||||
civ03 = actors["Civ03"];
|
||||
civ04 = actors["Civ04"];
|
||||
civ05 = actors["Civ05"];
|
||||
civ06 = actors["Civ06"];
|
||||
civ07 = actors["Civ07"];
|
||||
nr1 = actors["NODReinforceNthA"];
|
||||
nr2 = actors["NODReinforceNthB"];
|
||||
gr1 = actors["GDIReinforceNth"];
|
||||
Game.MoveViewport(nr1.Location.ToFloat2());
|
||||
Action afterFMV = () =>
|
||||
{
|
||||
Sound.PlayMusic(Rules.Music["aoi"]);
|
||||
};
|
||||
Game.RunAfterDelay(0, () => Media.PlayFMVFullscreen(w, "nod1pre.vqa", () =>
|
||||
Media.PlayFMVFullscreen(w, "nod1.vqa", afterFMV)));
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Cnc;
|
||||
using OpenRA.Mods.RA;
|
||||
using OpenRA.Mods.RA.Air;
|
||||
using OpenRA.Mods.RA.Move;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Mods.RA.Missions;
|
||||
using OpenRA.Mods.RA.Buildings;
|
||||
using OpenRA.Scripting;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Mods.Cnc.Missions
|
||||
{
|
||||
class Nod01ScriptInfo : TraitInfo<Nod01Script>, Requires<SpawnMapActorsInfo> { }
|
||||
|
||||
class Nod01Script : IHasObjectives, IWorldLoaded, ITick
|
||||
{
|
||||
public event Action<bool> OnObjectivesUpdated = notify => { };
|
||||
|
||||
public IEnumerable<Objective> Objectives { get { return new[] { killnikoomba, levelvillage }; } }
|
||||
|
||||
Objective killnikoomba = new Objective(ObjectiveType.Primary, KillNikoombaText, ObjectiveStatus.InProgress);
|
||||
Objective levelvillage = new Objective(ObjectiveType.Primary, LevelVillageText, ObjectiveStatus.Inactive);
|
||||
|
||||
const string KillNikoombaText = "Find Nikoomba. Once found he must be assasinated.";
|
||||
const string LevelVillageText = "Nikoomba has met his demise, now level the village.";
|
||||
|
||||
Player gdi;
|
||||
Player nod;
|
||||
|
||||
//actors and the likes go here
|
||||
Actor nikoomba;
|
||||
Actor vil01;
|
||||
Actor vil02;
|
||||
Actor vil03;
|
||||
Actor vil04;
|
||||
Actor vil05;
|
||||
Actor vil06;
|
||||
Actor vil07;
|
||||
Actor vil08;
|
||||
Actor vil09;
|
||||
Actor vil10;
|
||||
Actor vil11;
|
||||
Actor vil12;
|
||||
Actor vil13;
|
||||
Actor civ01;
|
||||
Actor civ02;
|
||||
Actor civ03;
|
||||
Actor civ04;
|
||||
Actor civ05;
|
||||
Actor civ06;
|
||||
Actor civ07;
|
||||
|
||||
//waypoints
|
||||
Actor nr1;
|
||||
Actor nr2;
|
||||
Actor gr1;
|
||||
|
||||
World world;
|
||||
|
||||
//in the allies01 script stuff was here not needed for me so far
|
||||
const string NRName = "E1";
|
||||
const string GRName = "E2";
|
||||
const string GRName2 = "JEEP";
|
||||
|
||||
void MissionFailed(string text)
|
||||
{
|
||||
MissionUtils.CoopMissionFailed(world, text, nod);
|
||||
}
|
||||
|
||||
void MissionAccomplished(string text)
|
||||
{
|
||||
MissionUtils.CoopMissionAccomplished(world, text, nod);
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (nod.WinState != WinState.Undefined) return;
|
||||
|
||||
//spawns nod reinf
|
||||
if (world.FrameNumber == 700)
|
||||
{
|
||||
NODReinforceNthA();
|
||||
Sound.Play("reinfor1.aud");
|
||||
}
|
||||
if (world.FrameNumber == 1400)
|
||||
{
|
||||
NODReinforceNthB();
|
||||
Sound.Play("reinfor1.aud");
|
||||
}
|
||||
// objectives
|
||||
if (killnikoomba.Status == ObjectiveStatus.InProgress)
|
||||
{
|
||||
if (nikoomba.Destroyed)
|
||||
{
|
||||
killnikoomba.Status = ObjectiveStatus.Completed;
|
||||
levelvillage.Status = ObjectiveStatus.InProgress;
|
||||
OnObjectivesUpdated(true);
|
||||
//DisplayObjective();
|
||||
//GDIReinforceNth();
|
||||
}
|
||||
}
|
||||
if (levelvillage.Status == ObjectiveStatus.InProgress)
|
||||
{
|
||||
if (vil01.Destroyed && vil02.Destroyed && vil03.Destroyed && vil04.Destroyed && vil05.Destroyed && vil06.Destroyed &&
|
||||
vil07.Destroyed && vil08.Destroyed && vil09.Destroyed && vil10.Destroyed && vil11.Destroyed && vil12.Destroyed &&
|
||||
vil13.Destroyed && civ01.Destroyed && civ02.Destroyed && civ03.Destroyed && civ04.Destroyed && civ05.Destroyed &&
|
||||
civ06.Destroyed && civ07.Destroyed)
|
||||
{
|
||||
levelvillage.Status = ObjectiveStatus.Completed;
|
||||
OnObjectivesUpdated(true);
|
||||
MissionAccomplished("Nikoomba was killed and the village was destroyed.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!world.Actors.Any(a => (a.Owner == nod) && a.IsInWorld && !a.IsDead()))
|
||||
{
|
||||
MissionFailed("The Nod forces in the area have been wiped out.");
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<Actor> UnitsNearActor(Actor actor, int range)
|
||||
{
|
||||
return world.FindActorsInCircle(actor.CenterPosition, WRange.FromCells(range))
|
||||
.Where(a => a.IsInWorld && a != world.WorldActor && !a.Destroyed && a.HasTrait<IPositionable>() && !a.Owner.NonCombatant);
|
||||
}
|
||||
|
||||
void NODReinforceNthA()
|
||||
{
|
||||
nr1 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr1.Location) });
|
||||
nr1 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr1.Location) });
|
||||
}
|
||||
|
||||
void NODReinforceNthB()
|
||||
{
|
||||
nr2 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr2.Location) });
|
||||
nr2 = world.CreateActor(true, NRName, new TypeDictionary { new OwnerInit(nod), new LocationInit(nr2.Location) });
|
||||
//nr1.QueueActivity(new Move.Move(nr1.Location - new CVec(0, 2)));
|
||||
}
|
||||
|
||||
void GDIReinforceNth()
|
||||
{
|
||||
gr1 = world.CreateActor(true, GRName, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) });
|
||||
gr1 = world.CreateActor(true, GRName, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) });
|
||||
gr1 = world.CreateActor(true, GRName2, new TypeDictionary { new OwnerInit(gdi), new LocationInit(gr1.Location) });
|
||||
//gr1.QueueActivity(new Move.Move(nr1.Location - new CVec(0, 2)));
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w)
|
||||
{
|
||||
world = w;
|
||||
gdi = w.Players.Single(p => p.InternalName == "GDI");
|
||||
nod = w.Players.Single(p => p.InternalName == "NOD");
|
||||
var actors = w.WorldActor.Trait<SpawnMapActors>().Actors;
|
||||
nikoomba = actors["Nikoomba"];
|
||||
vil01 = actors["Vil01"];
|
||||
vil02 = actors["Vil02"];
|
||||
vil03 = actors["Vil03"];
|
||||
vil04 = actors["Vil04"];
|
||||
vil05 = actors["Vil05"];
|
||||
vil06 = actors["Vil06"];
|
||||
vil07 = actors["Vil07"];
|
||||
vil08 = actors["Vil08"];
|
||||
vil09 = actors["Vil09"];
|
||||
vil10 = actors["Vil10"];
|
||||
vil11 = actors["Vil11"];
|
||||
vil12 = actors["Vil12"];
|
||||
vil13 = actors["Vil13"];
|
||||
civ01 = actors["Civ01"];
|
||||
civ02 = actors["Civ02"];
|
||||
civ03 = actors["Civ03"];
|
||||
civ04 = actors["Civ04"];
|
||||
civ05 = actors["Civ05"];
|
||||
civ06 = actors["Civ06"];
|
||||
civ07 = actors["Civ07"];
|
||||
nr1 = actors["NODReinforceNthA"];
|
||||
nr2 = actors["NODReinforceNthB"];
|
||||
gr1 = actors["GDIReinforceNth"];
|
||||
Game.MoveViewport(nr1.Location.ToFloat2());
|
||||
Action afterFMV = () =>
|
||||
{
|
||||
Sound.PlayMusic(Rules.Music["aoi"]);
|
||||
};
|
||||
Game.RunAfterDelay(0, () => Media.PlayFMVFullscreen(w, "nod1pre.vqa", () =>
|
||||
Media.PlayFMVFullscreen(w, "nod1.vqa", afterFMV)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,7 +763,7 @@ namespace OpenRA.Mods.RA.AI
|
||||
if (!buildableThings.Any()) return null;
|
||||
|
||||
var myUnits = p.World
|
||||
.ActorsWithTrait<IMove>()
|
||||
.ActorsWithTrait<IPositionable>()
|
||||
.Where(a => a.Actor.Owner == p)
|
||||
.Select(a => a.Actor.Info.Name).ToArray();
|
||||
|
||||
@@ -783,7 +783,7 @@ namespace OpenRA.Mods.RA.AI
|
||||
|
||||
int CountUnits(string unit, Player owner)
|
||||
{
|
||||
return world.ActorsWithTrait<IMove>().Where(a => a.Actor.Owner == owner && a.Actor.Info.Name == unit).Count();
|
||||
return world.ActorsWithTrait<IPositionable>().Where(a => a.Actor.Owner == owner && a.Actor.Info.Name == unit).Count();
|
||||
}
|
||||
|
||||
int? CountBuildingByCommonName(string commonName, Player owner)
|
||||
@@ -1028,7 +1028,7 @@ namespace OpenRA.Mods.RA.AI
|
||||
{
|
||||
var allEnemyUnits = world.Actors
|
||||
.Where(unit => p.Stances[unit.Owner] == Stance.Enemy && !unit.HasTrait<Husk>() &&
|
||||
unit.HasTrait<ITargetable>() && unit.HasTrait<IHasLocation>()).ToList();
|
||||
unit.HasTrait<ITargetable>()).ToList();
|
||||
|
||||
if (allEnemyUnits.Count > 0)
|
||||
return allEnemyUnits.ClosestTo(pos);
|
||||
@@ -1048,14 +1048,14 @@ namespace OpenRA.Mods.RA.AI
|
||||
|
||||
List<Actor> FindEnemyConstructionYards()
|
||||
{
|
||||
var bases = world.Actors.Where(a => p.Stances[a.Owner] == Stance.Enemy && a.HasTrait<IHasLocation>()
|
||||
&& !a.Destroyed && a.HasTrait<BaseBuilding>() && !a.HasTrait<Mobile>()).ToList();
|
||||
var bases = world.Actors.Where(a => p.Stances[a.Owner] == Stance.Enemy && !a.Destroyed
|
||||
&& a.HasTrait<BaseBuilding>() && !a.HasTrait<Mobile>()).ToList();
|
||||
return bases != null ? bases : new List<Actor>();
|
||||
}
|
||||
|
||||
Actor FindEnemyBuildingClosestToPos(WPos pos)
|
||||
{
|
||||
var closestBuilding = world.Actors.Where(a => p.Stances[a.Owner] == Stance.Enemy && a.HasTrait<IHasLocation>()
|
||||
var closestBuilding = world.Actors.Where(a => p.Stances[a.Owner] == Stance.Enemy
|
||||
&& !a.Destroyed && a.HasTrait<Building>()).ClosestTo(pos);
|
||||
return closestBuilding;
|
||||
}
|
||||
@@ -1145,7 +1145,7 @@ namespace OpenRA.Mods.RA.AI
|
||||
|
||||
void FindNewUnits(Actor self)
|
||||
{
|
||||
var newUnits = self.World.ActorsWithTrait<IMove>()
|
||||
var newUnits = self.World.ActorsWithTrait<IPositionable>()
|
||||
.Where(a => a.Actor.Owner == p && !a.Actor.HasTrait<BaseBuilding>()
|
||||
&& !activeUnits.Contains(a.Actor))
|
||||
.Select(a => a.Actor).ToArray();
|
||||
@@ -1424,12 +1424,12 @@ namespace OpenRA.Mods.RA.AI
|
||||
aggro[e.Attacker.Owner].Aggro += e.Damage;
|
||||
|
||||
//protected harvesters or building
|
||||
if (self.HasTrait<Harvester>() || self.HasTrait<Building>())
|
||||
if (e.Attacker.HasTrait<IHasLocation>() && (p.Stances[e.Attacker.Owner] == Stance.Enemy))
|
||||
{
|
||||
defenseCenter = e.Attacker.Location;
|
||||
ProtectOwn(e.Attacker);
|
||||
}
|
||||
if ((self.HasTrait<Harvester>() || self.HasTrait<Building>()) &&
|
||||
p.Stances[e.Attacker.Owner] == Stance.Enemy)
|
||||
{
|
||||
defenseCenter = e.Attacker.Location;
|
||||
ProtectOwn(e.Attacker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace OpenRA.Mods.RA.Activities
|
||||
var mobile = self.Trait<Mobile>();
|
||||
var to = target.CenterPosition;
|
||||
var from = self.CenterPosition;
|
||||
var speed = mobile.WorldMovementSpeedForCell(self, self.Location);
|
||||
var length = speed > 0 ? (int)((to - from).Length * 3 / speed) : 0;
|
||||
var speed = mobile.MovementSpeedForCell(self, self.Location);
|
||||
var length = speed > 0 ? (to - from).Length / speed : 0;
|
||||
|
||||
return Util.SequenceActivities(
|
||||
new Turn(Util.GetFacing(to - from, mobile.Facing)),
|
||||
|
||||
@@ -41,8 +41,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
mobile.IsMoving = true;
|
||||
|
||||
from = self.CenterPosition;
|
||||
var offset = MobileInfo.SubCellOffsets[targetMobile.fromSubCell];
|
||||
to = targetMobile.fromCell.CenterPosition + new WVec(offset.X * 1024 / Game.CellSize, offset.Y * 1024 / Game.CellSize, 0);
|
||||
to = targetMobile.fromCell.CenterPosition + MobileInfo.SubCellOffsets[targetMobile.fromSubCell];
|
||||
length = Math.Max((to - from).Length / speed.Range, 1);
|
||||
|
||||
self.Trait<RenderInfantry>().Attacking(self, Target.FromActor(target));
|
||||
@@ -56,7 +55,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
if (ticks == 0 && IsCanceled)
|
||||
return NextActivity;
|
||||
|
||||
mobile.AdjustPxPosition(self, PPos.FromWPosHackZ(WPos.LerpQuadratic(from, to, angle, ++ticks, length)));
|
||||
mobile.SetVisualPosition(self, WPos.LerpQuadratic(from, to, angle, ++ticks, length));
|
||||
if (ticks >= length)
|
||||
{
|
||||
mobile.SetLocation(mobile.toCell, mobile.toSubCell, mobile.toCell, mobile.toSubCell);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#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
|
||||
@@ -34,7 +34,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
Sound.Play(sound, self.CenterPosition);
|
||||
Sound.Play(sound, destination.CenterPosition);
|
||||
|
||||
self.Trait<ITeleportable>().SetPosition(self, destination);
|
||||
self.Trait<IPositionable>().SetPosition(self, destination);
|
||||
self.Generation++;
|
||||
|
||||
if (killCargo && self.HasTrait<Cargo>())
|
||||
@@ -68,7 +68,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
self.Trait<ITeleportable>().SetPosition(self, destination);
|
||||
self.Trait<IPositionable>().SetPosition(self, destination);
|
||||
self.Generation++;
|
||||
return NextActivity;
|
||||
}
|
||||
|
||||
@@ -90,9 +90,9 @@ namespace OpenRA.Mods.RA.Activities
|
||||
var mobile = actor.Trait<Mobile>();
|
||||
mobile.Facing = Util.GetFacing(exit - current, mobile.Facing );
|
||||
mobile.SetPosition(actor, exitTile.Value);
|
||||
mobile.AdjustPxPosition(actor, PPos.FromWPos(current));
|
||||
var speed = mobile.WorldMovementSpeedForCell(actor, exitTile.Value);
|
||||
var length = speed > 0 ? ((int)(exit - current).Length * 3 / speed) : 0;
|
||||
mobile.SetVisualPosition(actor, current);
|
||||
var speed = mobile.MovementSpeedForCell(actor, exitTile.Value);
|
||||
var length = speed > 0 ? (exit - current).Length / speed : 0;
|
||||
|
||||
w.Add(actor);
|
||||
actor.CancelActivity();
|
||||
|
||||
@@ -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, UsesInit<AltitudeInit>, UsesInit<LocationInit>, UsesInit<FacingInit>
|
||||
public class AircraftInfo : ITraitInfo, IFacingInfo, IOccupySpaceInfo, UsesInit<AltitudeInit>, UsesInit<LocationInit>, UsesInit<FacingInit>
|
||||
{
|
||||
public readonly int CruiseAltitude = 30;
|
||||
|
||||
[ActorReference]
|
||||
public readonly string[] RepairBuildings = { "fix" };
|
||||
[ActorReference]
|
||||
@@ -32,56 +32,47 @@ namespace OpenRA.Mods.RA.Air
|
||||
public readonly int Speed = 1;
|
||||
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 class Aircraft : IMove, IFacing, IOccupySpace, 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()
|
||||
{
|
||||
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 PPos PxPosition { get { return SubPxPosition.ToPPos(); } }
|
||||
public CPos TopLeft { get { return PxPosition.ToCPos(); } }
|
||||
[Sync] public WPos CenterPosition { get; private set; }
|
||||
public CPos TopLeft { get { return CenterPosition.ToCPos(); } }
|
||||
public IDisposable Reservation;
|
||||
public int ROT { get { return info.ROT; } }
|
||||
|
||||
readonly AircraftInfo Info;
|
||||
|
||||
public Aircraft(ActorInitializer init , AircraftInfo info)
|
||||
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();
|
||||
|
||||
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<LocationInit>())
|
||||
SetPosition(self, init.Get<LocationInit, CPos>());
|
||||
|
||||
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()
|
||||
{
|
||||
if (self.Trait<IMove>().Altitude != 0)
|
||||
if (self.CenterPosition.Z != 0)
|
||||
return null; // not on the ground.
|
||||
|
||||
return self.World.FindActorsInBox(self.CenterPosition, self.CenterPosition)
|
||||
.FirstOrDefault( a => a.HasTrait<Reservable>() );
|
||||
.FirstOrDefault(a => a.HasTrait<Reservable>());
|
||||
}
|
||||
|
||||
protected void ReserveSpawnBuilding()
|
||||
@@ -93,28 +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)
|
||||
{
|
||||
SetPxPosition(self, Util.CenterOfCell(cell));
|
||||
// Changes position, but not altitude
|
||||
CenterPosition = cell.CenterPosition + new WVec(0, 0, CenterPosition.Z);
|
||||
}
|
||||
|
||||
public void SetPxPosition(Actor self, PPos px)
|
||||
{
|
||||
SubPxPosition = px.ToPSubPos();
|
||||
}
|
||||
|
||||
public void AdjustPxPosition(Actor self, PPos px) { SetPxPosition(self, px); }
|
||||
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; }
|
||||
@@ -123,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)
|
||||
@@ -148,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);
|
||||
}
|
||||
|
||||
@@ -226,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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -24,14 +24,13 @@ namespace OpenRA.Mods.RA.Air
|
||||
|
||||
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)
|
||||
{
|
||||
// dont fire while landed
|
||||
return base.CanAttack(self, target)
|
||||
&& self.Trait<Aircraft>().Altitude > 0;
|
||||
return base.CanAttack(self, target) && self.CenterPosition.Z > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#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
|
||||
@@ -20,6 +20,7 @@ namespace OpenRA.Mods.RA
|
||||
public readonly string PilotActor = "E1";
|
||||
public readonly int SuccessRate = 50;
|
||||
public readonly string ChuteSound = "chute1.aud";
|
||||
public readonly WRange MinimumEjectHeight = new WRange(427);
|
||||
}
|
||||
|
||||
public class EjectOnDeath : INotifyKilled
|
||||
@@ -29,14 +30,15 @@ namespace OpenRA.Mods.RA
|
||||
var info = self.Info.Traits.Get<EjectOnDeathInfo>();
|
||||
var pilot = self.World.CreateActor(false, info.PilotActor.ToLowerInvariant(),
|
||||
new TypeDictionary { new OwnerInit(self.Owner) });
|
||||
var r = self.World.SharedRandom.Next(1, 100);
|
||||
var aircraft = self.Trait<IMove>();
|
||||
|
||||
if (IsSuitableCell(pilot, self.Location) && r > 100 - info.SuccessRate && aircraft.Altitude > 10
|
||||
var r = self.World.SharedRandom.Next(1, 100);
|
||||
var cp = self.CenterPosition;
|
||||
|
||||
if (IsSuitableCell(pilot, self.Location) && r > 100 - info.SuccessRate && cp.Z > info.MinimumEjectHeight.Range
|
||||
&& self.Owner.WinState != WinState.Lost)
|
||||
{
|
||||
self.World.AddFrameEndTask(w => w.Add(new Parachute(pilot, self.CenterPosition)));
|
||||
Sound.Play(info.ChuteSound, self.CenterPosition);
|
||||
self.World.AddFrameEndTask(w => w.Add(new Parachute(pilot, cp)));
|
||||
Sound.Play(info.ChuteSound, cp);
|
||||
}
|
||||
else
|
||||
pilot.Destroy();
|
||||
@@ -44,7 +46,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
bool IsSuitableCell(Actor actorToDrop, CPos p)
|
||||
{
|
||||
return actorToDrop.Trait<ITeleportable>().CanEnterCell(p);
|
||||
return actorToDrop.Trait<IPositionable>().CanEnterCell(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,15 +63,14 @@ 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;
|
||||
}
|
||||
|
||||
// Cannot be cancelled
|
||||
public override void Cancel( Actor self ) { }
|
||||
public override void Cancel(Actor self) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,49 +16,56 @@ namespace OpenRA.Mods.RA.Air
|
||||
{
|
||||
public class Fly : Activity
|
||||
{
|
||||
public readonly PPos Pos;
|
||||
readonly WPos pos;
|
||||
|
||||
Fly(PPos px) { Pos = px; }
|
||||
Fly(WPos pos) { this.pos = pos; }
|
||||
|
||||
public static Fly ToPx( PPos px ) { return new Fly( px ); }
|
||||
public static Fly ToCell(CPos pos) { return new Fly(Util.CenterOfCell(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); }
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
var cruiseAltitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude;
|
||||
|
||||
if (IsCanceled) return NextActivity;
|
||||
|
||||
var d = Pos - self.CenterLocation;
|
||||
if (d.LengthSquared < 50) /* close enough */
|
||||
if (IsCanceled)
|
||||
return NextActivity;
|
||||
|
||||
var aircraft = self.Trait<Aircraft>();
|
||||
// Close enough (ported from old code which checked length against sqrt(50) px)
|
||||
var d = pos - self.CenterPosition;
|
||||
if (d.HorizontalLengthSquared < 91022)
|
||||
return NextActivity;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public override IEnumerable<Target> GetTargets( Actor self )
|
||||
public override IEnumerable<Target> GetTargets(Actor self)
|
||||
{
|
||||
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);
|
||||
yield return Target.FromPos(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,43 +14,41 @@ namespace OpenRA.Mods.RA.Air
|
||||
{
|
||||
public class FlyAttack : Activity
|
||||
{
|
||||
readonly Target Target;
|
||||
readonly Target target;
|
||||
Activity inner;
|
||||
|
||||
public FlyAttack(Target target) { Target = target; }
|
||||
public FlyAttack(Target target) { this.target = target; }
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if( !Target.IsValid )
|
||||
Cancel( self );
|
||||
if (!target.IsValid)
|
||||
Cancel(self);
|
||||
|
||||
var limitedAmmo = self.TraitOrDefault<LimitedAmmo>();
|
||||
if( limitedAmmo != null && !limitedAmmo.HasAmmo() )
|
||||
Cancel( self );
|
||||
if (limitedAmmo != null && !limitedAmmo.HasAmmo())
|
||||
Cancel(self);
|
||||
|
||||
var attack = self.TraitOrDefault<AttackPlane>();
|
||||
if (attack != null)
|
||||
attack.DoAttack( self, Target );
|
||||
attack.DoAttack(self, target);
|
||||
|
||||
if( inner == null )
|
||||
if (inner == null)
|
||||
{
|
||||
if( IsCanceled )
|
||||
if (IsCanceled)
|
||||
return NextActivity;
|
||||
inner = Util.SequenceActivities(
|
||||
Fly.ToPx(Target.CenterLocation),
|
||||
new FlyTimed(50));
|
||||
|
||||
inner = Util.SequenceActivities(Fly.ToPos(target.CenterPosition), new FlyTimed(50));
|
||||
}
|
||||
inner = Util.RunActivity( self, inner );
|
||||
|
||||
inner = Util.RunActivity(self, inner);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public override void Cancel( Actor self )
|
||||
public override void Cancel(Actor self)
|
||||
{
|
||||
if( !IsCanceled )
|
||||
{
|
||||
if( inner != null )
|
||||
inner.Cancel( self );
|
||||
}
|
||||
if (!IsCanceled && inner != null)
|
||||
inner.Cancel(self);
|
||||
|
||||
// NextActivity must always be set to null:
|
||||
base.Cancel(self);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,15 +35,16 @@ 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;
|
||||
}
|
||||
|
||||
public override void Cancel( Actor self )
|
||||
public override void Cancel(Actor self)
|
||||
{
|
||||
base.Cancel(self);
|
||||
}
|
||||
|
||||
@@ -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,36 +17,35 @@ namespace OpenRA.Mods.RA.Air
|
||||
public class HeliAttack : Activity
|
||||
{
|
||||
Target target;
|
||||
public HeliAttack( Target target ) { this.target = target; }
|
||||
public HeliAttack(Target target) { this.target = target; }
|
||||
|
||||
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;
|
||||
}
|
||||
return Util.SequenceActivities(new HeliReturn(), NextActivity);
|
||||
|
||||
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 );
|
||||
attack.DoAttack(self, target);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -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,42 +16,56 @@ namespace OpenRA.Mods.RA.Air
|
||||
{
|
||||
class HeliFly : Activity
|
||||
{
|
||||
public readonly PPos Dest;
|
||||
public HeliFly(PPos dest)
|
||||
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)
|
||||
{
|
||||
Dest = dest;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
var dist = Dest - aircraft.PxPosition;
|
||||
if (Math.Abs(dist.X) < 2 && Math.Abs(dist.Y) < 2)
|
||||
// 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 move = helicopter.FlyStep(desiredFacing);
|
||||
if (dist.HorizontalLengthSquared < move.HorizontalLengthSquared)
|
||||
{
|
||||
aircraft.SubPxPosition = Dest.ToPSubPos();
|
||||
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;
|
||||
}
|
||||
|
||||
public override IEnumerable<Target> GetTargets( Actor self )
|
||||
public override IEnumerable<Target> GetTargets(Actor self)
|
||||
{
|
||||
yield return Target.FromPos(Dest);
|
||||
yield return Target.FromPos(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
return this;
|
||||
if (HeliFly.AdjustAltitude(self, helicopter, helicopter.Info.LandAltitude))
|
||||
return this;
|
||||
|
||||
return NextActivity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -19,16 +19,16 @@ namespace OpenRA.Mods.RA.Air
|
||||
static Actor ChooseHelipad(Actor self)
|
||||
{
|
||||
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));
|
||||
return self.World.Actors.Where(a => a.Owner == self.Owner).FirstOrDefault(
|
||||
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,23 +40,23 @@ 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(Util.CenterOfCell(nearestHpad.Location)));
|
||||
return Util.SequenceActivities(new HeliFly(nearestHpad.CenterPosition));
|
||||
}
|
||||
|
||||
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 : PVecInt.Zero;
|
||||
var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero;
|
||||
|
||||
return Util.SequenceActivities(
|
||||
new HeliFly(dest.Trait<IHasLocation>().PxPosition + offset),
|
||||
new HeliFly(dest.CenterPosition + offset),
|
||||
new Turn(initialFacing),
|
||||
new HeliLand(false, 0),
|
||||
new HeliLand(false),
|
||||
new Rearm(self),
|
||||
NextActivity);
|
||||
}
|
||||
|
||||
@@ -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,29 +17,31 @@ namespace OpenRA.Mods.RA.Air
|
||||
{
|
||||
class HelicopterInfo : AircraftInfo
|
||||
{
|
||||
public readonly int IdealSeparation = 40;
|
||||
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); }
|
||||
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 )
|
||||
public Helicopter(ActorInitializer init, HelicopterInfo info)
|
||||
: base(init, 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")
|
||||
@@ -48,12 +50,12 @@ namespace OpenRA.Mods.RA.Air
|
||||
|
||||
self.SetTargetLine(Target.FromCell(target), Color.Green);
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new HeliFly(Util.CenterOfCell(target)));
|
||||
self.QueueActivity(new HeliFly(target));
|
||||
|
||||
if (Info.LandWhenIdle)
|
||||
{
|
||||
self.QueueActivity(new Turn(Info.InitialFacing));
|
||||
self.QueueActivity(new HeliLand(true, Info.MinimalLandAltitude));
|
||||
self.QueueActivity(new HeliLand(true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,17 +70,17 @@ 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 : PVecInt.Zero;
|
||||
var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero;
|
||||
|
||||
self.SetTargetLine(Target.FromActor(order.TargetActor), Color.Green);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new HeliFly(order.TargetActor.Trait<IHasLocation>().PxPosition + offset));
|
||||
self.QueueActivity(new HeliFly(order.TargetActor.CenterPosition + offset));
|
||||
self.QueueActivity(new Turn(Info.InitialFacing));
|
||||
self.QueueActivity(new HeliLand(false, Info.MinimalLandAltitude));
|
||||
self.QueueActivity(new HeliLand(false));
|
||||
self.QueueActivity(new ResupplyAircraft());
|
||||
}
|
||||
}
|
||||
@@ -86,7 +88,7 @@ namespace OpenRA.Mods.RA.Air
|
||||
if (order.OrderString == "ReturnToBase")
|
||||
{
|
||||
self.CancelActivity();
|
||||
self.QueueActivity( new HeliReturn() );
|
||||
self.QueueActivity(new HeliReturn());
|
||||
}
|
||||
|
||||
if (order.OrderString == "Stop")
|
||||
@@ -96,7 +98,7 @@ namespace OpenRA.Mods.RA.Air
|
||||
if (Info.LandWhenIdle)
|
||||
{
|
||||
self.QueueActivity(new Turn(Info.InitialFacing));
|
||||
self.QueueActivity(new HeliLand(true, Info.MinimalLandAltitude));
|
||||
self.QueueActivity(new HeliLand(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,38 +112,42 @@ namespace OpenRA.Mods.RA.Air
|
||||
ReserveSpawnBuilding();
|
||||
}
|
||||
|
||||
/* repulsion only applies when we're flying */
|
||||
if (Altitude <= 0) return;
|
||||
// Repulsion only applies when we're flying!
|
||||
var altitude = CenterPosition.Z;
|
||||
var cruiseAltitude = Info.CruiseAltitude * 1024 / Game.CellSize;
|
||||
if (altitude != cruiseAltitude)
|
||||
return;
|
||||
|
||||
var separation = new WRange(Info.IdealSeparation * 1024 / Game.CellSize);
|
||||
var otherHelis = self.World.FindActorsInCircle(self.CenterPosition, separation)
|
||||
var otherHelis = self.World.FindActorsInCircle(self.CenterPosition, Info.IdealSeparation)
|
||||
.Where(a => a.HasTrait<Helicopter>());
|
||||
|
||||
var f = otherHelis
|
||||
.Select(h => GetRepulseForce(self, h))
|
||||
.Aggregate(PSubVec.Zero, (a, b) => a + b);
|
||||
.Aggregate(WVec.Zero, (a, b) => a + b);
|
||||
|
||||
// FIXME(jsd): not sure which units GetFacing accepts; code is unclear to me.
|
||||
int repulsionFacing = Util.GetFacing( f.ToInt2(), -1 );
|
||||
if( repulsionFacing != -1 )
|
||||
TickMove(PSubPos.PerPx * MovementSpeed, repulsionFacing);
|
||||
int repulsionFacing = Util.GetFacing(f, -1);
|
||||
if (repulsionFacing != -1)
|
||||
SetPosition(self, CenterPosition + FlyStep(repulsionFacing));
|
||||
}
|
||||
|
||||
// Returns a vector in subPx units
|
||||
public PSubVec GetRepulseForce(Actor self, Actor h)
|
||||
public WVec GetRepulseForce(Actor self, Actor other)
|
||||
{
|
||||
if (self == h)
|
||||
return PSubVec.Zero;
|
||||
if( h.Trait<Helicopter>().Altitude < Altitude )
|
||||
return PSubVec.Zero;
|
||||
var d = self.CenterLocation - h.CenterLocation;
|
||||
if (self == other || other.CenterPosition.Z < self.CenterPosition.Z)
|
||||
return WVec.Zero;
|
||||
|
||||
if (d.Length > Info.IdealSeparation)
|
||||
return PSubVec.Zero;
|
||||
var d = self.CenterPosition - other.CenterPosition;
|
||||
var distSq = d.HorizontalLengthSquared;
|
||||
if (distSq > Info.IdealSeparation.Range * Info.IdealSeparation.Range)
|
||||
return WVec.Zero;
|
||||
|
||||
if (d.LengthSquared < 1)
|
||||
return Util.SubPxVector[self.World.SharedRandom.Next(255)];
|
||||
return (5 * d.ToPSubVec()) / d.LengthSquared;
|
||||
if (distSq < 1)
|
||||
{
|
||||
var yaw = self.World.SharedRandom.Next(0, 1023);
|
||||
var rot = new WRot(WAngle.Zero, WAngle.Zero, new WAngle(yaw));
|
||||
return new WVec(1024, 0, 0).Rotate(rot);
|
||||
}
|
||||
|
||||
return (d * 1024 * 8) / (int)distSq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,29 +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 d = Target.CenterPosition - self.CenterPosition;
|
||||
if (d.LengthSquared < 256*256) // close enough (1/4 cell)
|
||||
if (IsCanceled)
|
||||
return NextActivity;
|
||||
|
||||
var aircraft = self.Trait<Aircraft>();
|
||||
var plane = self.Trait<Plane>();
|
||||
var d = target.CenterPosition - self.CenterPosition;
|
||||
|
||||
if (aircraft.Altitude > 0)
|
||||
--aircraft.Altitude;
|
||||
// The next move would overshoot, so just set the final position
|
||||
var move = plane.FlyStep(plane.Facing);
|
||||
if (d.HorizontalLengthSquared < move.HorizontalLengthSquared)
|
||||
{
|
||||
plane.SetPosition(self, target.CenterPosition);
|
||||
return NextActivity;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 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
|
||||
{
|
||||
[Sync] public PVecInt RTBPathHash;
|
||||
public readonly PlaneInfo Info;
|
||||
[Sync] public WPos RTBPathHash;
|
||||
|
||||
public Plane( ActorInitializer init, PlaneInfo info )
|
||||
: base( init, info ) { }
|
||||
public Plane(ActorInitializer init, PlaneInfo 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;
|
||||
|
||||
@@ -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)
|
||||
@@ -38,13 +37,13 @@ namespace OpenRA.Mods.RA.Air
|
||||
|
||||
// i'd prefer something we own
|
||||
var someBuilding = self.World.ActorsWithTrait<Building>()
|
||||
.Select( a => a.Actor )
|
||||
.Select(a => a.Actor)
|
||||
.FirstOrDefault(a => a.Owner == self.Owner);
|
||||
|
||||
// failing that, something unlikely to shoot at us
|
||||
if (someBuilding == null)
|
||||
someBuilding = self.World.ActorsWithTrait<Building>()
|
||||
.Select( a => a.Actor )
|
||||
.Select(a => a.Actor)
|
||||
.FirstOrDefault(a => self.Owner.Stances[a.Owner] == Stance.Ally);
|
||||
|
||||
if (someBuilding == null)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -19,8 +19,7 @@ namespace OpenRA.Mods.RA.Air
|
||||
{
|
||||
bool isCalculated;
|
||||
Actor dest;
|
||||
|
||||
PPos w1, w2, w3; /* tangent points to turn circles */
|
||||
WPos w1, w2, w3;
|
||||
|
||||
public static Actor ChooseAirfield(Actor self, bool unreservedOnly)
|
||||
{
|
||||
@@ -35,53 +34,60 @@ namespace OpenRA.Mods.RA.Air
|
||||
|
||||
void Calculate(Actor self)
|
||||
{
|
||||
if (dest == null || Reservable.IsReserved(dest)) dest = ChooseAirfield(self, true);
|
||||
if (dest == null || Reservable.IsReserved(dest))
|
||||
dest = ChooseAirfield(self, true);
|
||||
|
||||
if (dest == null) return;
|
||||
if (dest == null)
|
||||
return;
|
||||
|
||||
var plane = self.Trait<Plane>();
|
||||
var planeInfo = self.Info.Traits.Get<PlaneInfo>();
|
||||
var res = dest.TraitOrDefault<Reservable>();
|
||||
if (res != null)
|
||||
{
|
||||
plane.UnReserve();
|
||||
plane.reservation = res.Reserve(dest, self, plane);
|
||||
plane.Reservation = res.Reserve(dest, self, plane);
|
||||
}
|
||||
|
||||
var landPos = dest.CenterLocation;
|
||||
var aircraft = self.Trait<Aircraft>();
|
||||
var landPos = dest.CenterPosition;
|
||||
|
||||
var speed = .2f * aircraft.MovementSpeed;
|
||||
// Distance required for descent.
|
||||
var landDistance = planeInfo.CruiseAltitude * 1024 * 1024 / (Game.CellSize * plane.Info.MaximumPitch.Tan());
|
||||
var altitude = planeInfo.CruiseAltitude * 1024 / Game.CellSize;
|
||||
|
||||
/* if the aircraft is on the ground, it will take off to the cruise altitude first before approaching */
|
||||
var altitude = aircraft.Altitude;
|
||||
if (altitude == 0) altitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude;
|
||||
// Land towards the east
|
||||
var approachStart = landPos + new WVec(-landDistance, 0, altitude);
|
||||
|
||||
var approachStart = landPos.ToInt2() - new float2(altitude * speed, 0);
|
||||
var turnRadius = (128f / self.Info.Traits.Get<AircraftInfo>().ROT) * speed / (float)Math.PI;
|
||||
// Add 10% to the turning radius to ensure we have enough room
|
||||
var speed = plane.MovementSpeed * 1024 / (Game.CellSize * 5);
|
||||
var turnRadius = (int)(141 * speed / planeInfo.ROT / (float)Math.PI);
|
||||
|
||||
/* work out the center points */
|
||||
var fwd = -float2.FromAngle(aircraft.Facing / 128f * (float)Math.PI);
|
||||
var side = new float2(-fwd.Y, fwd.X); /* rotate */
|
||||
// Find the center of the turning circles for clockwise and counterclockwise turns
|
||||
var angle = WAngle.FromFacing(plane.Facing);
|
||||
var fwd = -new WVec(angle.Sin(), angle.Cos(), 0);
|
||||
|
||||
// Work out whether we should turn clockwise or counter-clockwise for approach
|
||||
var side = new WVec(-fwd.Y, fwd.X, fwd.Z);
|
||||
var approachDelta = self.CenterPosition - approachStart;
|
||||
var sideTowardBase = new[] { side, -side }
|
||||
.OrderBy(a => float2.Dot(a, self.CenterLocation.ToInt2() - approachStart))
|
||||
.OrderBy(a => WVec.Dot(a, approachDelta))
|
||||
.First();
|
||||
|
||||
var c1 = self.CenterLocation.ToInt2() + turnRadius * sideTowardBase;
|
||||
var c2 = approachStart + new float2(0, turnRadius * Math.Sign(self.CenterLocation.Y - approachStart.Y)); // above or below start point
|
||||
// Calculate the tangent line that joins the turning circles at the current and approach positions
|
||||
var cp = self.CenterPosition + turnRadius * sideTowardBase / 1024;
|
||||
var posCenter = new WPos(cp.X, cp.Y, altitude);
|
||||
var approachCenter = approachStart + new WVec(0, turnRadius * Math.Sign(self.CenterPosition.Y - approachStart.Y), 0);
|
||||
var tangentDirection = approachCenter - posCenter;
|
||||
var tangentOffset = new WVec(-tangentDirection.Y, tangentDirection.X, 0) * turnRadius / tangentDirection.Length;
|
||||
|
||||
/* work out tangent points */
|
||||
var d = c2 - c1;
|
||||
var e = (turnRadius / d.Length) * d;
|
||||
var f = new float2(-e.Y, e.X); /* rotate */
|
||||
// TODO: correctly handle CCW <-> CW turns
|
||||
if (tangentOffset.X > 0)
|
||||
tangentOffset = -tangentOffset;
|
||||
|
||||
/* TODO: support internal tangents, too! */
|
||||
|
||||
if (f.X > 0) f = -f;
|
||||
|
||||
w1 = (PPos)(c1 + f).ToInt2();
|
||||
w2 = (PPos)(c2 + f).ToInt2();
|
||||
w3 = (PPos)(approachStart).ToInt2();
|
||||
plane.RTBPathHash = (PVecInt)w1 + (PVecInt)w2 + (PVecInt)w3;
|
||||
w1 = posCenter + tangentOffset;
|
||||
w2 = approachCenter + tangentOffset;
|
||||
w3 = approachStart;
|
||||
plane.RTBPathHash = w1 + (WVec)w2 + (WVec)w3;
|
||||
|
||||
isCalculated = true;
|
||||
}
|
||||
@@ -93,12 +99,12 @@ namespace OpenRA.Mods.RA.Air
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled)
|
||||
return NextActivity;
|
||||
if (self.IsDead())
|
||||
if (IsCanceled || self.IsDead())
|
||||
return NextActivity;
|
||||
|
||||
if (!isCalculated)
|
||||
Calculate(self);
|
||||
|
||||
if (dest == null)
|
||||
{
|
||||
var nearestAfld = ChooseAirfield(self, false);
|
||||
@@ -111,9 +117,9 @@ namespace OpenRA.Mods.RA.Air
|
||||
}
|
||||
|
||||
return Util.SequenceActivities(
|
||||
Fly.ToPx(w1),
|
||||
Fly.ToPx(w2),
|
||||
Fly.ToPx(w3),
|
||||
Fly.ToPos(w1),
|
||||
Fly.ToPos(w2),
|
||||
Fly.ToPos(w3),
|
||||
new Land(Target.FromActor(dest)),
|
||||
NextActivity);
|
||||
}
|
||||
|
||||
@@ -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,19 +24,19 @@ 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
|
||||
: info.GroundedTargetTypes; }
|
||||
get { return (self.CenterPosition.Z > 0) ? info.TargetTypes
|
||||
: info.GroundedTargetTypes; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
// Note: facing is only used by the legacy positioning code
|
||||
// The world coordinate model uses Actor.Orientation
|
||||
public void CheckFire(Actor self, AttackBase attack, IMove move, IFacing facing, Target target)
|
||||
public void CheckFire(Actor self, AttackBase attack, IFacing facing, Target target)
|
||||
{
|
||||
if (FireDelay > 0) return;
|
||||
|
||||
@@ -120,8 +120,6 @@ namespace OpenRA.Mods.RA
|
||||
return;
|
||||
|
||||
var barrel = Barrels[Burst % Barrels.Length];
|
||||
var destMove = target.IsActor ? target.Actor.TraitOrDefault<IMove>() : null;
|
||||
|
||||
var muzzlePosition = self.CenterPosition + MuzzleOffset(self, barrel);
|
||||
var legacyMuzzlePosition = PPos.FromWPos(muzzlePosition);
|
||||
var legacyMuzzleAltitude = Game.CellSize*muzzlePosition.Z/1024;
|
||||
@@ -135,8 +133,8 @@ namespace OpenRA.Mods.RA
|
||||
src = legacyMuzzlePosition,
|
||||
srcAltitude = legacyMuzzleAltitude,
|
||||
|
||||
dest = target.CenterLocation,
|
||||
destAltitude = destMove != null ? destMove.Altitude : 0,
|
||||
dest = PPos.FromWPos(target.CenterPosition),
|
||||
destAltitude = target.CenterPosition.Z * Game.CellSize / 1024,
|
||||
|
||||
facing = legacyFacing,
|
||||
|
||||
|
||||
@@ -89,12 +89,12 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public virtual void DoAttack(Actor self, Target target)
|
||||
{
|
||||
if( !CanAttack( self, target ) ) return;
|
||||
if (!CanAttack(self, target))
|
||||
return;
|
||||
|
||||
var move = self.TraitOrDefault<IMove>();
|
||||
var facing = self.TraitOrDefault<IFacing>();
|
||||
foreach (var a in Armaments)
|
||||
a.CheckFire(self, this, move, facing, target);
|
||||
a.CheckFire(self, this, facing, target);
|
||||
}
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
|
||||
@@ -38,10 +38,9 @@ namespace OpenRA.Mods.RA
|
||||
if (!target.IsInRange(self.CenterPosition, range))
|
||||
return;
|
||||
|
||||
var move = self.TraitOrDefault<IMove>();
|
||||
var facing = self.TraitOrDefault<IFacing>();
|
||||
foreach (var a in Armaments)
|
||||
a.CheckFire(self, this, move, facing, target);
|
||||
a.CheckFire(self, this, facing, target);
|
||||
|
||||
if (target.Actor != null)
|
||||
target.Actor.ChangeOwner(self.Owner);
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
foreach (var c in TileSprites[currentTemplate].Keys)
|
||||
foreach (var a in self.World.ActorMap.GetUnitsAt(c))
|
||||
if (a.HasTrait<IMove>() && !a.Trait<IMove>().CanEnterCell(c))
|
||||
if (a.HasTrait<IPositionable>() && !a.Trait<IPositionable>().CanEnterCell(c))
|
||||
a.Kill(self);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenRA.Mods.RA.Buildings
|
||||
public class GivesBuildableAreaInfo : TraitInfo<GivesBuildableArea> {}
|
||||
public class GivesBuildableArea {}
|
||||
|
||||
public class BuildingInfo : ITraitInfo, UsesInit<LocationInit>
|
||||
public class BuildingInfo : ITraitInfo, IOccupySpaceInfo, UsesInit<LocationInit>
|
||||
{
|
||||
[Desc("If negative, it will drain power, if positive, it will provide power.")]
|
||||
public readonly int Power = 0;
|
||||
@@ -96,7 +96,6 @@ namespace OpenRA.Mods.RA.Buildings
|
||||
[Sync] readonly CPos topLeft;
|
||||
|
||||
PowerManager PlayerPower;
|
||||
PPos pxPosition;
|
||||
|
||||
[Sync] public bool Locked; /* shared activity lock: undeploy, sell, capture, etc */
|
||||
|
||||
@@ -110,7 +109,7 @@ namespace OpenRA.Mods.RA.Buildings
|
||||
public void Unlock() { Locked = false; }
|
||||
|
||||
public CPos TopLeft { get { return topLeft; } }
|
||||
public PPos PxPosition { get { return pxPosition; } }
|
||||
public WPos CenterPosition { get; private set; }
|
||||
|
||||
public IEnumerable<string> ProvidesPrerequisites { get { yield return self.Info.Name; } }
|
||||
|
||||
@@ -124,8 +123,7 @@ namespace OpenRA.Mods.RA.Buildings
|
||||
occupiedCells = FootprintUtils.UnpathableTiles( self.Info.Name, Info, TopLeft )
|
||||
.Select(c => Pair.New(c, SubCell.FullCell)).ToArray();
|
||||
|
||||
var position = topLeft.CenterPosition + FootprintUtils.CenterOffset(Info);
|
||||
pxPosition = PPos.FromWPosHackZ(position);
|
||||
CenterPosition = topLeft.CenterPosition + FootprintUtils.CenterOffset(Info);
|
||||
}
|
||||
|
||||
public int GetPowerUsage()
|
||||
|
||||
@@ -17,14 +17,14 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
public class CargoInfo : ITraitInfo
|
||||
public class CargoInfo : ITraitInfo, Requires<IOccupySpaceInfo>
|
||||
{
|
||||
public readonly int MaxWeight = 0;
|
||||
public readonly int PipCount = 0;
|
||||
public readonly string[] Types = { };
|
||||
public readonly int UnloadFacing = 0;
|
||||
public readonly string[] InitialUnits = { };
|
||||
public readonly int minimalUnloadAltitude = 0;
|
||||
public readonly WRange MaximumUnloadAltitude = WRange.Zero;
|
||||
|
||||
public object Create( ActorInitializer init ) { return new Cargo( init, this ); }
|
||||
}
|
||||
@@ -92,8 +92,8 @@ namespace OpenRA.Mods.RA
|
||||
return false;
|
||||
|
||||
// Cannot unload mid-air
|
||||
var move = self.TraitOrDefault<IMove>();
|
||||
if (move != null && move.Altitude > info.minimalUnloadAltitude)
|
||||
var ios = self.TraitOrDefault<IOccupySpace>();
|
||||
if (ios != null && ios.CenterPosition.Z > info.MaximumUnloadAltitude.Range)
|
||||
return false;
|
||||
|
||||
// TODO: Check if there is a free tile to unload to
|
||||
@@ -106,8 +106,7 @@ namespace OpenRA.Mods.RA
|
||||
return false;
|
||||
|
||||
// Cannot load mid-air
|
||||
var move = self.TraitOrDefault<IMove>();
|
||||
return move == null || move.Altitude == info.minimalUnloadAltitude;
|
||||
return self.CenterPosition.Z <= info.MaximumUnloadAltitude.Range;
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
|
||||
@@ -56,12 +56,14 @@ namespace OpenRA.Mods.RA
|
||||
var weapon = Rules.Weapons[info.Weapon.ToLowerInvariant()];
|
||||
dropDelay = weapon.ROF;
|
||||
|
||||
var centerLocation = PPos.FromWPos(self.CenterPosition);
|
||||
var altitude = self.CenterPosition.Z * Game.CellSize / 1024;
|
||||
var args = new ProjectileArgs
|
||||
{
|
||||
srcAltitude = self.Trait<IMove>().Altitude,
|
||||
srcAltitude = altitude,
|
||||
destAltitude = 0,
|
||||
src = self.CenterLocation,
|
||||
dest = self.CenterLocation,
|
||||
src = centerLocation,
|
||||
dest = centerLocation,
|
||||
facing = self.Trait<IFacing>().Facing,
|
||||
firedBy = self,
|
||||
weapon = weapon
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public bool CanJumpTo(CPos xy, bool ignoreVis)
|
||||
{
|
||||
var movement = self.TraitOrDefault<IMove>();
|
||||
var movement = self.TraitOrDefault<IPositionable>();
|
||||
|
||||
if (chargeTick <= 0 // Can jump
|
||||
&& (self.Location - xy).Length <= Info.JumpDistance // Within jump range
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
@@ -9,6 +9,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -19,38 +20,43 @@ namespace OpenRA.Mods.RA
|
||||
public readonly bool ExplodeInstead = false;
|
||||
public readonly string ChronoshiftSound = "chrono2.aud";
|
||||
|
||||
public object Create(ActorInitializer init) { return new Chronoshiftable(this); }
|
||||
public object Create(ActorInitializer init) { return new Chronoshiftable(init, this); }
|
||||
}
|
||||
|
||||
public class Chronoshiftable : ITick, ISync, ISelectionBar
|
||||
{
|
||||
// Return-to-sender logic
|
||||
[Sync] CPos chronoshiftOrigin;
|
||||
[Sync] int chronoshiftReturnTicks = 0;
|
||||
readonly ChronoshiftableInfo info;
|
||||
Actor chronosphere;
|
||||
bool killCargo;
|
||||
int TotalTicks;
|
||||
readonly ChronoshiftableInfo info;
|
||||
int duration;
|
||||
|
||||
public Chronoshiftable(ChronoshiftableInfo info)
|
||||
// Return-to-sender logic
|
||||
[Sync] public CPos Origin;
|
||||
[Sync] public int ReturnTicks = 0;
|
||||
|
||||
public Chronoshiftable(ActorInitializer init, ChronoshiftableInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
|
||||
if (init.Contains<ChronoshiftReturnInit>())
|
||||
ReturnTicks = init.Get<ChronoshiftReturnInit, int>();
|
||||
|
||||
if (init.Contains<ChronoshiftOriginInit>())
|
||||
Origin = init.Get<ChronoshiftOriginInit, CPos>();
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (chronoshiftReturnTicks <= 0)
|
||||
if (ReturnTicks <= 0)
|
||||
return;
|
||||
|
||||
if (chronoshiftReturnTicks > 0)
|
||||
chronoshiftReturnTicks--;
|
||||
|
||||
// Return to original location
|
||||
if (chronoshiftReturnTicks == 0)
|
||||
if (--ReturnTicks == 0)
|
||||
{
|
||||
self.CancelActivity();
|
||||
|
||||
// TODO: need a new Teleport method that will move to the closest available cell
|
||||
self.QueueActivity(new Teleport(chronosphere, chronoshiftOrigin, killCargo, info.ChronoshiftSound));
|
||||
self.QueueActivity(new Teleport(chronosphere, Origin, killCargo, info.ChronoshiftSound));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,25 +64,27 @@ namespace OpenRA.Mods.RA
|
||||
public virtual bool CanChronoshiftTo(Actor self, CPos targetLocation)
|
||||
{
|
||||
// TODO: Allow enemy units to be chronoshifted into bad terrain to kill them
|
||||
return (self.HasTrait<ITeleportable>() && self.Trait<ITeleportable>().CanEnterCell(targetLocation));
|
||||
return self.HasTrait<IPositionable>() && self.Trait<IPositionable>().CanEnterCell(targetLocation);
|
||||
}
|
||||
|
||||
public virtual bool Teleport(Actor self, CPos targetLocation, int duration, bool killCargo, Actor chronosphere)
|
||||
{
|
||||
if (info.ExplodeInstead) // some things appear chronoshiftable, but instead they just die.
|
||||
// some things appear chronoshiftable, but instead they just die.
|
||||
if (info.ExplodeInstead)
|
||||
{
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
// damage is inflicted by the chronosphere
|
||||
if (!self.Destroyed) self.InflictDamage(chronosphere, int.MaxValue, null);
|
||||
if (!self.Destroyed)
|
||||
self.InflictDamage(chronosphere, int.MaxValue, null);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Set up return-to-sender info
|
||||
chronoshiftOrigin = self.Location;
|
||||
chronoshiftReturnTicks = duration;
|
||||
TotalTicks = duration;
|
||||
Origin = self.Location;
|
||||
ReturnTicks = duration;
|
||||
this.duration = duration;
|
||||
this.chronosphere = chronosphere;
|
||||
this.killCargo = killCargo;
|
||||
|
||||
@@ -90,11 +98,27 @@ namespace OpenRA.Mods.RA
|
||||
// Show the remaining time as a bar
|
||||
public float GetValue()
|
||||
{
|
||||
if (chronoshiftReturnTicks == 0) // otherwise an empty bar is rendered all the time
|
||||
if (ReturnTicks == 0) // otherwise an empty bar is rendered all the time
|
||||
return 0f;
|
||||
|
||||
return (float)chronoshiftReturnTicks / TotalTicks;
|
||||
return (float)ReturnTicks / duration;
|
||||
}
|
||||
|
||||
public Color GetColor() { return Color.White; }
|
||||
}
|
||||
|
||||
public class ChronoshiftReturnInit : IActorInit<int>
|
||||
{
|
||||
[FieldFromYamlKey] readonly int value = 0;
|
||||
public ChronoshiftReturnInit() { }
|
||||
public ChronoshiftReturnInit(int init) { value = init; }
|
||||
public int Value(World world) { return value; }
|
||||
}
|
||||
|
||||
public class ChronoshiftOriginInit : IActorInit<CPos>
|
||||
{
|
||||
[FieldFromYamlKey] readonly CPos value;
|
||||
public ChronoshiftOriginInit(CPos init) { value = init; }
|
||||
public CPos Value(World world) { return value; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Mods.RA.Buildings;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class CrateInfo : ITraitInfo, Requires<RenderSpritesInfo>
|
||||
class CrateInfo : ITraitInfo, IOccupySpaceInfo, Requires<RenderSpritesInfo>
|
||||
{
|
||||
public readonly int Lifetime = 5; // Seconds
|
||||
public readonly string[] TerrainTypes = { };
|
||||
@@ -24,26 +24,25 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
|
||||
// ITeleportable is required for paradrop
|
||||
class Crate : ITick, IOccupySpace, ITeleportable, ICrushable, ISync, INotifyParachuteLanded
|
||||
class Crate : ITick, IPositionable, ICrushable, ISync, INotifyParachuteLanded
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly CrateInfo info;
|
||||
bool collected;
|
||||
|
||||
[Sync] int ticks;
|
||||
[Sync] public CPos Location;
|
||||
CrateInfo Info;
|
||||
bool collected;
|
||||
|
||||
public Crate(ActorInitializer init, CrateInfo info)
|
||||
{
|
||||
this.self = init.self;
|
||||
this.info = info;
|
||||
|
||||
if (init.Contains<LocationInit>())
|
||||
{
|
||||
this.Location = init.Get<LocationInit, CPos>();
|
||||
PxPosition = Util.CenterOfCell(Location);
|
||||
}
|
||||
this.Info = info;
|
||||
SetPosition(self, init.Get<LocationInit, CPos>());
|
||||
}
|
||||
|
||||
public void WarnCrush(Actor crusher) {}
|
||||
public void WarnCrush(Actor crusher) { }
|
||||
|
||||
public void OnCrush(Actor crusher)
|
||||
{
|
||||
@@ -78,27 +77,22 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if( ++ticks >= Info.Lifetime * 25 )
|
||||
if (++ticks >= info.Lifetime * 25)
|
||||
self.Destroy();
|
||||
}
|
||||
|
||||
public CPos TopLeft { get { return Location; } }
|
||||
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { yield return Pair.New( Location, SubCell.FullCell); }
|
||||
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { yield return Pair.New(Location, SubCell.FullCell); }
|
||||
|
||||
public PPos PxPosition { get; private set; }
|
||||
|
||||
public void SetPxPosition(Actor self, PPos px)
|
||||
{
|
||||
SetPosition( self, px.ToCPos() );
|
||||
}
|
||||
|
||||
public void AdjustPxPosition(Actor self, PPos px) { SetPxPosition(self, px); }
|
||||
public WPos CenterPosition { get; private set; }
|
||||
public void SetPosition(Actor self, WPos pos) { SetPosition(self, pos.ToCPos()); }
|
||||
public void SetVisualPosition(Actor self, WPos pos) { SetPosition(self, pos.ToCPos()); }
|
||||
|
||||
public bool CanEnterCell(CPos cell)
|
||||
{
|
||||
if (!self.World.Map.IsInMap(cell.X, cell.Y)) return false;
|
||||
var type = self.World.GetTerrainType(cell);
|
||||
if (!Info.TerrainTypes.Contains(type))
|
||||
if (!info.TerrainTypes.Contains(type))
|
||||
return false;
|
||||
|
||||
if (self.World.WorldActor.Trait<BuildingInfluence>().GetBuildingAt(cell) != null) return false;
|
||||
@@ -109,18 +103,18 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public void SetPosition(Actor self, CPos cell)
|
||||
{
|
||||
if( self.IsInWorld )
|
||||
if (self.IsInWorld)
|
||||
self.World.ActorMap.Remove(self, this);
|
||||
|
||||
Location = cell;
|
||||
PxPosition = Util.CenterOfCell(cell);
|
||||
CenterPosition = cell.CenterPosition;
|
||||
|
||||
var seq = self.World.GetTerrainInfo(cell).IsWater ? "water" : "land";
|
||||
var rs = self.Trait<RenderSprites>();
|
||||
if (seq != rs.anim.CurrentSequence.Name)
|
||||
rs.anim.PlayRepeating(seq);
|
||||
|
||||
if( self.IsInWorld )
|
||||
if (self.IsInWorld)
|
||||
self.World.ActorMap.Add(self, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -97,9 +97,9 @@ namespace OpenRA.Mods.RA.Effects
|
||||
// In pixels
|
||||
var dist = Args.target.CenterLocation + offset - PxPosition;
|
||||
|
||||
var targetAltitude = 0;
|
||||
if (Args.target.IsValid && Args.target.IsActor && Args.target.Actor.HasTrait<IMove>())
|
||||
targetAltitude = Args.target.Actor.Trait<IMove>().Altitude;
|
||||
var targetAltitude = 0;
|
||||
if (Args.target.IsValid)
|
||||
targetAltitude = Args.target.CenterPosition.Z * Game.CellSize / 1024;
|
||||
|
||||
var jammed = Info.Jammable && world.ActorsWithTrait<JamsMissiles>().Any(tp =>
|
||||
(tp.Actor.CenterLocation - PxPosition).ToCVec().Length <= tp.Trait.Range
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA.Effects
|
||||
parachuteOffset = pai.Offset;
|
||||
|
||||
// Adjust x,y to match the target subcell
|
||||
cargo.Trait<ITeleportable>().SetPosition(cargo, dropPosition.ToCPos());
|
||||
cargo.Trait<IPositionable>().SetPosition(cargo, dropPosition.ToCPos());
|
||||
var cp = cargo.CenterPosition;
|
||||
pos = new WPos(cp.X, cp.Y, dropPosition.Z);
|
||||
}
|
||||
|
||||
@@ -9,86 +9,78 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Mods.RA.Move;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class HuskInfo : ITraitInfo, IFacingInfo
|
||||
class HuskInfo : ITraitInfo, IOccupySpaceInfo, IFacingInfo
|
||||
{
|
||||
public object Create( ActorInitializer init ) { return new Husk( init ); }
|
||||
public readonly string[] AllowedTerrain = { };
|
||||
|
||||
public object Create(ActorInitializer init) { return new Husk(init, this); }
|
||||
|
||||
public int GetInitialFacing() { return 128; }
|
||||
}
|
||||
|
||||
class Husk : IOccupySpace, IFacing, ISync
|
||||
class Husk : IPositionable, IFacing, ISync
|
||||
{
|
||||
[Sync] CPos location;
|
||||
|
||||
[Sync] public PPos PxPosition { get; set; }
|
||||
readonly HuskInfo info;
|
||||
readonly Actor self;
|
||||
|
||||
[Sync] public CPos TopLeft { get; private set; }
|
||||
[Sync] public WPos CenterPosition { get; private set; }
|
||||
[Sync] public int Facing { get; set; }
|
||||
|
||||
public int ROT { get { return 0; } }
|
||||
|
||||
public Husk(ActorInitializer init)
|
||||
public Husk(ActorInitializer init, HuskInfo info)
|
||||
{
|
||||
var self = init.self;
|
||||
location = init.Get<LocationInit, CPos>();
|
||||
PxPosition = init.Contains<CenterLocationInit>() ? init.Get<CenterLocationInit, PPos>() : Util.CenterOfCell(location);
|
||||
Facing = init.Contains<FacingInit>() ? init.Get<FacingInit,int>() : 128;
|
||||
this.info = info;
|
||||
this.self = init.self;
|
||||
|
||||
var speed = init.Contains<HuskSpeedInit>() ? init.Get<HuskSpeedInit,int>() : 0;
|
||||
if (speed > 0)
|
||||
{
|
||||
var to = Util.CenterOfCell(location);
|
||||
var length = (int)((to - PxPosition).Length * 3 / speed);
|
||||
self.QueueActivity(new DragHusk(PxPosition, to, length, this));
|
||||
}
|
||||
TopLeft = init.Get<LocationInit, CPos>();
|
||||
var ppos = init.Contains<CenterLocationInit>() ? init.Get<CenterLocationInit, PPos>() : Util.CenterOfCell(TopLeft);
|
||||
CenterPosition = ppos.ToWPos(0);
|
||||
Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 128;
|
||||
|
||||
var speed = init.Contains<HuskSpeedInit>() ? init.Get<HuskSpeedInit, int>() : 0;
|
||||
var distance = (TopLeft.CenterPosition - CenterPosition).Length;
|
||||
if (speed > 0 && distance > 0)
|
||||
self.QueueActivity(new Drag(CenterPosition, TopLeft.CenterPosition, distance / speed));
|
||||
}
|
||||
|
||||
public CPos TopLeft { get { return location; } }
|
||||
|
||||
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); }
|
||||
|
||||
class DragHusk : Activity
|
||||
public bool CanEnterCell(CPos cell)
|
||||
{
|
||||
Husk husk;
|
||||
PPos endLocation;
|
||||
PPos startLocation;
|
||||
int length;
|
||||
if (!self.World.Map.IsInMap(cell.X, cell.Y))
|
||||
return false;
|
||||
|
||||
public DragHusk(PPos start, PPos end, int length, Husk husk)
|
||||
{
|
||||
startLocation = start;
|
||||
endLocation = end;
|
||||
this.length = length;
|
||||
this.husk = husk;
|
||||
}
|
||||
if (!info.AllowedTerrain.Contains(self.World.GetTerrainType(cell)))
|
||||
return false;
|
||||
|
||||
int ticks = 0;
|
||||
public override Activity Tick( Actor self )
|
||||
{
|
||||
if (ticks >= length || length <= 1)
|
||||
{
|
||||
husk.PxPosition = endLocation;
|
||||
return NextActivity;
|
||||
}
|
||||
return !self.World.ActorMap.AnyUnitsAt(cell);
|
||||
}
|
||||
|
||||
husk.PxPosition = PPos.Lerp(startLocation, endLocation, ticks++, length - 1);
|
||||
return this;
|
||||
}
|
||||
public void SetPosition(Actor self, CPos cell) { SetPosition(self, cell.CenterPosition); }
|
||||
public void SetVisualPosition(Actor self, WPos pos) { CenterPosition = pos; }
|
||||
|
||||
public override IEnumerable<Target> GetTargets( Actor self ) { yield break; }
|
||||
public override void Cancel( Actor self ) { }
|
||||
public void SetPosition(Actor self, WPos pos)
|
||||
{
|
||||
self.World.ActorMap.Remove(self, this);
|
||||
CenterPosition = pos;
|
||||
TopLeft = pos.ToCPos();
|
||||
self.World.ActorMap.Add(self, this);
|
||||
}
|
||||
}
|
||||
|
||||
public class HuskSpeedInit : IActorInit<int>
|
||||
{
|
||||
[FieldFromYamlKey] public readonly int value = 0;
|
||||
[FieldFromYamlKey] readonly int value = 0;
|
||||
public HuskSpeedInit() { }
|
||||
public HuskSpeedInit( int init ) { value = init; }
|
||||
public int Value( World world ) { return value; }
|
||||
public HuskSpeedInit(int init) { value = init; }
|
||||
public int Value(World world) { return value; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,16 +21,14 @@ namespace OpenRA.Mods.RA
|
||||
[ActorReference]
|
||||
public readonly string HuskActor = null;
|
||||
|
||||
public object Create( ActorInitializer init ) { return new LeavesHusk(this); }
|
||||
public object Create(ActorInitializer init) { return new LeavesHusk(this); }
|
||||
}
|
||||
|
||||
public class LeavesHusk : INotifyKilled
|
||||
{
|
||||
LeavesHuskInfo Info;
|
||||
public LeavesHusk(LeavesHuskInfo info)
|
||||
{
|
||||
Info = info;
|
||||
}
|
||||
LeavesHuskInfo info;
|
||||
|
||||
public LeavesHusk(LeavesHuskInfo info) { this.info = info; }
|
||||
|
||||
public void Killed(Actor self, AttackInfo e)
|
||||
{
|
||||
@@ -54,23 +52,30 @@ 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)
|
||||
td.Add(new FacingInit( facing.Facing ));
|
||||
td.Add(new FacingInit(facing.Facing));
|
||||
|
||||
// TODO: This will only take the first turret if there are multiple
|
||||
// This isn't a problem with the current units, but may be a problem for mods
|
||||
var turreted = self.TraitsImplementing<Turreted>().FirstOrDefault();
|
||||
if (turreted != null)
|
||||
td.Add( new TurretFacingInit(turreted.turretFacing) );
|
||||
td.Add(new TurretFacingInit(turreted.turretFacing));
|
||||
|
||||
var chronoshiftable = self.TraitOrDefault<Chronoshiftable>();
|
||||
if (chronoshiftable != null && chronoshiftable.ReturnTicks > 0)
|
||||
{
|
||||
td.Add(new ChronoshiftOriginInit(chronoshiftable.Origin));
|
||||
td.Add(new ChronoshiftReturnInit(chronoshiftable.ReturnTicks));
|
||||
}
|
||||
|
||||
var huskActor = self.TraitsImplementing<IHuskModifier>()
|
||||
.Select(ihm => ihm.HuskActor(self))
|
||||
.FirstOrDefault(a => a != null);
|
||||
|
||||
w.CreateActor(huskActor ?? Info.HuskActor, td);
|
||||
w.CreateActor(huskActor ?? info.HuskActor, td);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class MineInfo : ITraitInfo
|
||||
class MineInfo : ITraitInfo, IOccupySpaceInfo
|
||||
{
|
||||
public readonly string[] CrushClasses = { };
|
||||
public readonly bool AvoidFriendly = true;
|
||||
@@ -61,7 +61,7 @@ namespace OpenRA.Mods.RA
|
||||
public CPos TopLeft { get { return location; } }
|
||||
|
||||
public IEnumerable<Pair<CPos, SubCell>> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); }
|
||||
public PPos PxPosition { get { return Util.CenterOfCell( location ); } }
|
||||
public WPos CenterPosition { get { return location.CenterPosition; } }
|
||||
}
|
||||
|
||||
/* tag trait for stuff that shouldnt trigger mines */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#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
|
||||
@@ -60,7 +60,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
if (order.OrderString == "PlaceMinefield")
|
||||
{
|
||||
var movement = self.Trait<IMove>();
|
||||
var movement = self.Trait<IPositionable>();
|
||||
|
||||
minefield = GetMinefieldCells(minefieldStart, order.TargetLocation,
|
||||
self.Info.Traits.Get<MinelayerInfo>().MinefieldDepth)
|
||||
@@ -130,7 +130,7 @@ namespace OpenRA.Mods.RA
|
||||
if (!minelayer.IsInWorld)
|
||||
return;
|
||||
|
||||
var movement = minelayer.Trait<IMove>();
|
||||
var movement = minelayer.Trait<IPositionable>();
|
||||
var minefield = GetMinefieldCells(minefieldStart, lastMousePos,
|
||||
minelayer.Info.Traits.Get<MinelayerInfo>().MinefieldDepth)
|
||||
.Where(p => movement.CanEnterCell(p)).ToArray();
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace OpenRA.Mods.RA.Missions
|
||||
if (yak == null || (yak != null && !yak.IsDead() && (yak.GetCurrentActivity() is FlyCircle || yak.IsIdle)))
|
||||
{
|
||||
var alliedUnitsNearYakPoint = world.FindAliveCombatantActorsInCircle(yakAttackPoint.CenterPosition, WRange.FromCells(10))
|
||||
.Where(a => a.Owner != soviets && a.HasTrait<IMove>() && a != tanya && a != einstein && a != engineer);
|
||||
.Where(a => a.Owner != soviets && a.HasTrait<IPositionable>() && a != tanya && a != einstein && a != engineer);
|
||||
if (alliedUnitsNearYakPoint.Any())
|
||||
YakStrafe(alliedUnitsNearYakPoint);
|
||||
}
|
||||
@@ -384,7 +384,7 @@ namespace OpenRA.Mods.RA.Missions
|
||||
bool AlliesNearTown()
|
||||
{
|
||||
return world.FindAliveCombatantActorsInCircle(townPoint.CenterPosition, WRange.FromCells(AlliedTownTransferRange))
|
||||
.Any(a => a.Owner == allies1 && a.HasTrait<IMove>());
|
||||
.Any(a => a.Owner == allies1 && a.HasTrait<IPositionable>());
|
||||
}
|
||||
|
||||
void TransferTownUnitsToAllies()
|
||||
@@ -399,7 +399,7 @@ namespace OpenRA.Mods.RA.Missions
|
||||
var sovietAttackUnits = world.FindAliveCombatantActorsInCircle(sovietTownAttackPoint1.CenterPosition, WRange.FromCells(SovietTownAttackGroupRange))
|
||||
.Union(world.FindAliveCombatantActorsInCircle(sovietTownAttackPoint2.CenterPosition, WRange.FromCells(SovietTownAttackGroupRange)))
|
||||
.Union(world.FindAliveCombatantActorsInCircle(townPoint.CenterPosition, WRange.FromCells(AlliedTownTransferRange)))
|
||||
.Where(a => a.HasTrait<IMove>() && a.Owner == soviets);
|
||||
.Where(a => a.HasTrait<IPositionable>() && a.Owner == soviets);
|
||||
|
||||
foreach (var unit in sovietAttackUnits)
|
||||
unit.QueueActivity(new AttackMove.AttackMoveActivity(unit, new Move.Move(townPoint.Location, SovietTownMoveNearEnough)));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace OpenRA.Mods.RA.Missions
|
||||
var enemies = world.Actors.Where(u => u.Owner == creeps && u.HasTrait<ITargetable>()
|
||||
&& ((u.HasTrait<Building>() && !u.HasTrait<Wall>() && !u.HasTrait<Bridge>()) || u.HasTrait<Mobile>()) && !u.IsDead() && u.IsInWorld);
|
||||
|
||||
var enemy = enemies.OrderBy(u => (attacker.CenterPosition - u.CenterPosition).LengthSquared).FirstOrDefault();
|
||||
var enemy = enemies.ClosestTo(attacker);
|
||||
if (enemy != null)
|
||||
attacker.QueueActivity(new AttackMove.AttackMoveActivity(attacker, new Attack(Target.FromActor(enemy), WRange.FromCells(3))));
|
||||
else
|
||||
|
||||
@@ -217,14 +217,14 @@ namespace OpenRA.Mods.RA.Missions
|
||||
cargo.Load(chinook, world.CreateActor(false, ChinookCargo.Random(world.SharedRandom), allies, null, null));
|
||||
|
||||
var exit = lz.Info.Traits.WithInterface<ExitInfo>().FirstOrDefault();
|
||||
var offset = exit != null ? exit.SpawnOffsetVector : PVecInt.Zero;
|
||||
var offset = (exit != null) ? exit.SpawnOffsetVector : WVec.Zero;
|
||||
|
||||
chinook.QueueActivity(new HeliFly(lz.CenterLocation + 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 HeliLand(false, 0));
|
||||
chinook.QueueActivity(new HeliLand(false));
|
||||
chinook.QueueActivity(new UnloadCargo(true));
|
||||
chinook.QueueActivity(new Wait(150));
|
||||
chinook.QueueActivity(new HeliFly(Util.CenterOfCell(entry)));
|
||||
chinook.QueueActivity(new HeliFly(entry));
|
||||
chinook.QueueActivity(new RemoveSelf());
|
||||
}
|
||||
|
||||
|
||||
@@ -79,11 +79,10 @@ namespace OpenRA.Mods.RA.Missions
|
||||
{
|
||||
var enemies = world.Actors.Where(u => u.IsInWorld && !u.IsDead() && (u.Owner == multi0)
|
||||
&& ((u.HasTrait<Building>() && !u.HasTrait<Mobile>())));
|
||||
var targetEnemy = enemies.OrderBy(u => (self.CenterPosition - u.CenterPosition).LengthSquared).FirstOrDefault();
|
||||
|
||||
var targetEnemy = enemies.ClosestTo(self);
|
||||
if (targetEnemy != null)
|
||||
{
|
||||
self.QueueActivity(new AttackMove.AttackMoveActivity(self, new Attack(Target.FromActor(targetEnemy), WRange.FromCells(6))));
|
||||
}
|
||||
}
|
||||
|
||||
void SendVehicles()
|
||||
|
||||
@@ -45,12 +45,12 @@ namespace OpenRA.Mods.RA.Missions
|
||||
public static Actor ExtractUnitWithChinook(World world, Player owner, Actor unit, CPos entry, CPos lz, CPos exit)
|
||||
{
|
||||
var chinook = world.CreateActor("tran", new TypeDictionary { new OwnerInit(owner), new LocationInit(entry) });
|
||||
chinook.QueueActivity(new HeliFly(Util.CenterOfCell(lz)));
|
||||
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(Util.CenterOfCell(exit)));
|
||||
chinook.QueueActivity(new HeliFly(exit));
|
||||
chinook.QueueActivity(new RemoveSelf());
|
||||
return chinook;
|
||||
}
|
||||
@@ -60,13 +60,13 @@ namespace OpenRA.Mods.RA.Missions
|
||||
var unit = world.CreateActor(false, unitName, new TypeDictionary { new OwnerInit(owner) });
|
||||
var chinook = world.CreateActor("tran", new TypeDictionary { new OwnerInit(owner), new LocationInit(entry) });
|
||||
chinook.Trait<Cargo>().Load(chinook, unit);
|
||||
chinook.QueueActivity(new HeliFly(Util.CenterOfCell(lz)));
|
||||
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));
|
||||
chinook.QueueActivity(new HeliFly(Util.CenterOfCell(exit)));
|
||||
chinook.QueueActivity(new HeliFly(exit));
|
||||
chinook.QueueActivity(new RemoveSelf());
|
||||
return Pair.New(chinook, unit);
|
||||
}
|
||||
@@ -106,7 +106,7 @@ namespace OpenRA.Mods.RA.Missions
|
||||
|
||||
public static bool AreaSecuredWithUnits(World world, Player player, WPos location, WRange range)
|
||||
{
|
||||
var units = world.FindAliveCombatantActorsInCircle(location, range).Where(a => a.HasTrait<IMove>());
|
||||
var units = world.FindAliveCombatantActorsInCircle(location, range).Where(a => a.HasTrait<IPositionable>());
|
||||
return units.Any() && units.All(a => a.Owner == player);
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ namespace OpenRA.Mods.RA.Missions
|
||||
var enemies = self.World.Actors.Where(u => u.AppearsHostileTo(self) && u.Owner == enemyPlayer
|
||||
&& ((u.HasTrait<Building>() && !u.HasTrait<Wall>()) || (u.HasTrait<Mobile>() && !u.HasTrait<Aircraft>())) && u.IsInWorld && !u.IsDead());
|
||||
|
||||
var enemy = enemies.OrderBy(u => (self.CenterPosition - u.CenterPosition).LengthSquared).FirstOrDefault();
|
||||
var enemy = enemies.ClosestTo(self);
|
||||
if (enemy != null)
|
||||
self.QueueActivity(queued, new AttackMove.AttackMoveActivity(self, new Attack(Target.FromActor(enemy), WRange.FromCells(3))));
|
||||
}
|
||||
|
||||
@@ -126,8 +126,7 @@ namespace OpenRA.Mods.RA.Missions
|
||||
{
|
||||
var bridge = world.Actors
|
||||
.Where(a => a.HasTrait<Bridge>() && !a.IsDead())
|
||||
.OrderBy(a => (startJeep.CenterPosition - a.CenterPosition).LengthSquared)
|
||||
.First();
|
||||
.ClosestTo(startJeep);
|
||||
Combat.DoExplosion(bridge, "Demolish", bridge.CenterPosition);
|
||||
world.WorldActor.Trait<ScreenShaker>().AddEffect(15, bridge.CenterPosition, 6);
|
||||
bridge.Kill(bridge);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
@@ -185,7 +185,7 @@ namespace OpenRA.Mods.RA.Missions
|
||||
var units = world.CreateActor((sovietInfantry).Random(world.SharedRandom), new TypeDictionary { new LocationInit(sovietinfantryentry1.Location), new OwnerInit(soviets) });
|
||||
units.QueueActivity(new Move.Move(sovietinfantryrally1.Location, 3));
|
||||
var unitsincircle = world.FindAliveCombatantActorsInCircle(sovietinfantryrally1.CenterPosition, WRange.FromCells(10))
|
||||
.Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait<IMove>());
|
||||
.Where(a => a.Owner == soviets && a.IsIdle && a.HasTrait<IPositionable>());
|
||||
if (unitsincircle.Count() >= sovietInfantryGroupSize)
|
||||
{
|
||||
foreach (var scatteredunits in unitsincircle)
|
||||
@@ -211,11 +211,10 @@ namespace OpenRA.Mods.RA.Missions
|
||||
{
|
||||
var enemies = world.Actors.Where(u => u.IsInWorld && !u.IsDead() && (u.Owner == allies)
|
||||
&& ((u.HasTrait<Building>() && !u.HasTrait<Wall>()) || u.HasTrait<Mobile>()));
|
||||
var targetEnemy = enemies.OrderBy(u => (self.CenterPosition - u.CenterPosition).LengthSquared).FirstOrDefault();
|
||||
|
||||
var targetEnemy = enemies.ClosestTo(self);
|
||||
if (targetEnemy != null)
|
||||
{
|
||||
self.QueueActivity(new AttackMove.AttackMoveActivity(self, new Attack(Target.FromActor(targetEnemy), WRange.FromCells(3))));
|
||||
}
|
||||
}
|
||||
|
||||
void ManageSovietUnits()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
@@ -299,7 +299,7 @@ namespace OpenRA.Mods.RA.Missions
|
||||
void ManageSovietUnits()
|
||||
{
|
||||
var units = world.FindAliveCombatantActorsInCircle(sovietrally.CenterPosition, WRange.FromCells(3))
|
||||
.Where(u => u.IsIdle && u.HasTrait<IMove>() && u.HasTrait<AttackBase>() && u.Owner == soviets);
|
||||
.Where(u => u.IsIdle && u.HasTrait<IPositionable>() && u.HasTrait<AttackBase>() && u.Owner == soviets);
|
||||
if (units.Count() >= sovietAttackGroupSize)
|
||||
{
|
||||
foreach (var unit in units)
|
||||
|
||||
@@ -26,30 +26,36 @@ namespace OpenRA.Mods.RA.Move
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public override Activity Tick( Actor self )
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
var mobile = self.Trait<Mobile>();
|
||||
var positionable = self.Trait<IPositionable>();
|
||||
var mobile = positionable as Mobile;
|
||||
|
||||
var pos = length > 1
|
||||
? WPos.Lerp(start, end, ticks, length - 1)
|
||||
: end;
|
||||
|
||||
mobile.PxPosition = PPos.FromWPos(pos);
|
||||
positionable.SetVisualPosition(self, pos);
|
||||
if (++ticks >= length)
|
||||
{
|
||||
mobile.IsMoving = false;
|
||||
if (mobile != null)
|
||||
mobile.IsMoving = false;
|
||||
|
||||
return NextActivity;
|
||||
}
|
||||
|
||||
mobile.IsMoving = true;
|
||||
if (mobile != null)
|
||||
mobile.IsMoving = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IEnumerable<Target> GetTargets( Actor self )
|
||||
public override IEnumerable<Target> GetTargets(Actor self)
|
||||
{
|
||||
yield return Target.FromPos(end);
|
||||
}
|
||||
|
||||
// Cannot be cancelled
|
||||
public override void Cancel( Actor self ) { }
|
||||
public override void Cancel(Actor self) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ using OpenRA.Traits;
|
||||
namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
[Desc("Unit is able to move.")]
|
||||
public class MobileInfo : ITraitInfo, IFacingInfo, UsesInit<FacingInit>, UsesInit<LocationInit>, UsesInit<SubCellInit>
|
||||
public class MobileInfo : ITraitInfo, IOccupySpaceInfo, IFacingInfo, UsesInit<FacingInit>, UsesInit<LocationInit>, UsesInit<SubCellInit>
|
||||
{
|
||||
[FieldLoader.LoadUsing("LoadSpeeds")]
|
||||
[Desc("Set Water: 0 for ground units and lower the value on rough terrain.")]
|
||||
@@ -35,7 +35,6 @@ namespace OpenRA.Mods.RA.Move
|
||||
public readonly bool OnRails = false;
|
||||
[Desc("Allow multiple (infantry) units in one cell.")]
|
||||
public readonly bool SharesCell = false;
|
||||
public readonly int Altitude;
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new Mobile(init, this); }
|
||||
|
||||
@@ -81,14 +80,14 @@ namespace OpenRA.Mods.RA.Move
|
||||
return passability.ToBits();
|
||||
}
|
||||
|
||||
public static readonly Dictionary<SubCell, PVecInt> SubCellOffsets = new Dictionary<SubCell, PVecInt>()
|
||||
public static readonly Dictionary<SubCell, WVec> SubCellOffsets = new Dictionary<SubCell, WVec>()
|
||||
{
|
||||
{SubCell.TopLeft, new PVecInt(-7,-6)},
|
||||
{SubCell.TopRight, new PVecInt(6,-6)},
|
||||
{SubCell.Center, new PVecInt(0,0)},
|
||||
{SubCell.BottomLeft, new PVecInt(-7,6)},
|
||||
{SubCell.BottomRight, new PVecInt(6,6)},
|
||||
{SubCell.FullCell, new PVecInt(0,0)},
|
||||
{SubCell.TopLeft, new WVec(-299, -256, 0)},
|
||||
{SubCell.TopRight, new WVec(256, -256, 0)},
|
||||
{SubCell.Center, new WVec(0, 0, 0)},
|
||||
{SubCell.BottomLeft, new WVec(-299, 256, 0)},
|
||||
{SubCell.BottomRight, new WVec(256, 256, 0)},
|
||||
{SubCell.FullCell, new WVec(0, 0, 0)},
|
||||
};
|
||||
|
||||
static bool IsMovingInMyDirection(Actor self, Actor other)
|
||||
@@ -145,7 +144,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
public int GetInitialFacing() { return InitialFacing; }
|
||||
}
|
||||
|
||||
public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IOccupySpace, IMove, IFacing, ISync
|
||||
public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IFacing, ISync
|
||||
{
|
||||
public readonly Actor self;
|
||||
public readonly MobileInfo Info;
|
||||
@@ -163,11 +162,9 @@ namespace OpenRA.Mods.RA.Move
|
||||
set { __facing = value; }
|
||||
}
|
||||
|
||||
[Sync] public int Altitude { get; set; }
|
||||
|
||||
public int ROT { get { return Info.ROT; } }
|
||||
|
||||
[Sync] public PPos PxPosition { get; set; }
|
||||
[Sync] public WPos CenterPosition { get; private set; }
|
||||
[Sync] public CPos fromCell { get { return __fromCell; } }
|
||||
[Sync] public CPos toCell { get { return __toCell; } }
|
||||
|
||||
@@ -204,31 +201,36 @@ namespace OpenRA.Mods.RA.Move
|
||||
if (init.Contains<LocationInit>())
|
||||
{
|
||||
this.__fromCell = this.__toCell = init.Get<LocationInit, CPos>();
|
||||
this.PxPosition = Util.CenterOfCell(fromCell) + MobileInfo.SubCellOffsets[fromSubCell];
|
||||
SetVisualPosition(self, fromCell.CenterPosition + MobileInfo.SubCellOffsets[fromSubCell]);
|
||||
}
|
||||
|
||||
this.Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing;
|
||||
this.Altitude = init.Contains<AltitudeInit>() ? init.Get<AltitudeInit, int>() : 0;
|
||||
|
||||
if (init.Contains<AltitudeInit>())
|
||||
{
|
||||
var z = init.Get<AltitudeInit, int>() * 1024 / Game.CellSize;
|
||||
SetVisualPosition(self, CenterPosition + new WVec(0, 0, z - CenterPosition.Z));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPosition(Actor self, CPos cell)
|
||||
{
|
||||
SetLocation(cell,fromSubCell, cell,fromSubCell);
|
||||
PxPosition = Util.CenterOfCell(fromCell) + MobileInfo.SubCellOffsets[fromSubCell];
|
||||
SetVisualPosition(self, fromCell.CenterPosition + MobileInfo.SubCellOffsets[fromSubCell]);
|
||||
FinishedMoving(self);
|
||||
}
|
||||
|
||||
public void SetPxPosition(Actor self, PPos px)
|
||||
public void SetPosition(Actor self, WPos pos)
|
||||
{
|
||||
var cell = px.ToCPos();
|
||||
var cell = pos.ToCPos();
|
||||
SetLocation(cell,fromSubCell, cell,fromSubCell);
|
||||
PxPosition = px;
|
||||
SetVisualPosition(self, pos);
|
||||
FinishedMoving(self);
|
||||
}
|
||||
|
||||
public void AdjustPxPosition(Actor self, PPos px) /* visual hack only */
|
||||
public void SetVisualPosition(Actor self, WPos pos)
|
||||
{
|
||||
PxPosition = px;
|
||||
CenterPosition = pos;
|
||||
}
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders { get { yield return new MoveOrderTargeter(Info); } }
|
||||
@@ -422,12 +424,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
decimal speed = Info.Speed * Info.TerrainSpeeds[type].Speed;
|
||||
foreach (var t in self.TraitsImplementing<ISpeedModifier>())
|
||||
speed *= t.GetSpeedModifier();
|
||||
return (int)(speed / 100);
|
||||
}
|
||||
|
||||
public int WorldMovementSpeedForCell(Actor self, CPos cell)
|
||||
{
|
||||
return MovementSpeedForCell(self, cell) * 1024 / Game.CellSize;
|
||||
return (int)(speed / 100) * 1024 / (3 * Game.CellSize);
|
||||
}
|
||||
|
||||
public void AddInfluence()
|
||||
|
||||
@@ -20,11 +20,13 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
class Move : Activity
|
||||
{
|
||||
static readonly List<CPos> NoPath = new List<CPos>();
|
||||
|
||||
CPos? destination;
|
||||
WRange nearEnough;
|
||||
public List<CPos> path;
|
||||
List<CPos> path;
|
||||
Func<Actor, Mobile, List<CPos>> getPath;
|
||||
public Actor ignoreBuilding;
|
||||
Actor ignoreBuilding;
|
||||
|
||||
// For dealing with blockers
|
||||
bool hasWaited;
|
||||
@@ -35,9 +37,9 @@ namespace OpenRA.Mods.RA.Move
|
||||
// Ignores lane bias and nearby units
|
||||
public Move(CPos destination)
|
||||
{
|
||||
this.getPath = (self,mobile) =>
|
||||
this.getPath = (self, mobile) =>
|
||||
self.World.WorldActor.Trait<PathFinder>().FindPath(
|
||||
PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, destination, false )
|
||||
PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, destination, false)
|
||||
.WithoutLaneBias());
|
||||
this.destination = destination;
|
||||
this.nearEnough = WRange.Zero;
|
||||
@@ -45,29 +47,28 @@ namespace OpenRA.Mods.RA.Move
|
||||
|
||||
// Hack for legacy code
|
||||
public Move(CPos destination, int nearEnough)
|
||||
: this(destination, WRange.FromCells(nearEnough)) {}
|
||||
: this(destination, WRange.FromCells(nearEnough)) { }
|
||||
|
||||
public Move(CPos destination, WRange nearEnough)
|
||||
{
|
||||
this.getPath = (self,mobile) => self.World.WorldActor.Trait<PathFinder>().FindUnitPath( mobile.toCell, destination, self );
|
||||
this.getPath = (self, mobile) => self.World.WorldActor.Trait<PathFinder>()
|
||||
.FindUnitPath(mobile.toCell, destination, self);
|
||||
this.destination = destination;
|
||||
this.nearEnough = nearEnough;
|
||||
}
|
||||
|
||||
public Move(CPos destination, Actor ignoreBuilding)
|
||||
{
|
||||
this.getPath = (self,mobile) =>
|
||||
this.getPath = (self, mobile) =>
|
||||
self.World.WorldActor.Trait<PathFinder>().FindPath(
|
||||
PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, destination, false)
|
||||
.WithIgnoredBuilding(ignoreBuilding)
|
||||
);
|
||||
.WithIgnoredBuilding(ignoreBuilding));
|
||||
|
||||
this.destination = destination;
|
||||
this.nearEnough = WRange.Zero;
|
||||
this.ignoreBuilding = ignoreBuilding;
|
||||
}
|
||||
|
||||
static readonly List<CPos> NoPath = new List<CPos>();
|
||||
public Move(Target target, WRange range)
|
||||
{
|
||||
this.getPath = (self, mobile) =>
|
||||
@@ -85,7 +86,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
|
||||
public Move(Func<List<CPos>> getPath)
|
||||
{
|
||||
this.getPath = (_1,_2) => getPath();
|
||||
this.getPath = (_1, _2) => getPath();
|
||||
this.destination = null;
|
||||
this.nearEnough = WRange.Zero;
|
||||
}
|
||||
@@ -110,15 +111,6 @@ namespace OpenRA.Mods.RA.Move
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
var mobile = self.Trait<Mobile>();
|
||||
var info = self.Info.Traits.Get<MobileInfo>();
|
||||
|
||||
if (mobile.Altitude != info.Altitude)
|
||||
{
|
||||
if (mobile.Altitude < info.Altitude)
|
||||
++mobile.Altitude;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
if (destination == mobile.toCell)
|
||||
return NextActivity;
|
||||
@@ -132,7 +124,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
}
|
||||
|
||||
path = EvalPath(self, mobile);
|
||||
SanityCheckPath( mobile );
|
||||
SanityCheckPath(mobile);
|
||||
}
|
||||
|
||||
if (path.Count == 0)
|
||||
@@ -151,7 +143,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
var firstFacing = Util.GetFacing(dir, mobile.Facing);
|
||||
if (firstFacing != mobile.Facing)
|
||||
{
|
||||
path.Add( nextCell.Value.First );
|
||||
path.Add(nextCell.Value.First);
|
||||
return Util.SequenceActivities(new Turn(firstFacing), this);
|
||||
}
|
||||
else
|
||||
@@ -159,12 +151,11 @@ namespace OpenRA.Mods.RA.Move
|
||||
mobile.SetLocation(mobile.fromCell, mobile.fromSubCell, nextCell.Value.First, nextCell.Value.Second);
|
||||
var move = new MoveFirstHalf(
|
||||
this,
|
||||
Util.CenterOfCell(mobile.fromCell) + MobileInfo.SubCellOffsets[mobile.fromSubCell],
|
||||
mobile.fromCell.CenterPosition + MobileInfo.SubCellOffsets[mobile.fromSubCell],
|
||||
Util.BetweenCells(mobile.fromCell, mobile.toCell) + (MobileInfo.SubCellOffsets[mobile.fromSubCell] + MobileInfo.SubCellOffsets[mobile.toSubCell]) / 2,
|
||||
mobile.Facing,
|
||||
mobile.Facing,
|
||||
0
|
||||
);
|
||||
0);
|
||||
|
||||
return move;
|
||||
}
|
||||
@@ -206,7 +197,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
// Are we close enough?
|
||||
var cellRange = nearEnough.Range / 1024;
|
||||
if ((mobile.toCell - destination.Value).LengthSquared <= cellRange*cellRange)
|
||||
if ((mobile.toCell - destination.Value).LengthSquared <= cellRange * cellRange)
|
||||
{
|
||||
path.Clear();
|
||||
return null;
|
||||
@@ -255,9 +246,9 @@ namespace OpenRA.Mods.RA.Move
|
||||
return Pair.New(nextCell, subCell);
|
||||
}
|
||||
|
||||
public override void Cancel( Actor self )
|
||||
public override void Cancel(Actor self)
|
||||
{
|
||||
path = new List<CPos>(0);
|
||||
path = NoPath;
|
||||
base.Cancel(self);
|
||||
}
|
||||
|
||||
@@ -272,13 +263,13 @@ namespace OpenRA.Mods.RA.Move
|
||||
|
||||
abstract class MovePart : Activity
|
||||
{
|
||||
public readonly Move move;
|
||||
public readonly PPos from, to;
|
||||
public readonly int fromFacing, toFacing;
|
||||
public int moveFraction;
|
||||
public readonly int moveFractionTotal;
|
||||
protected readonly Move move;
|
||||
protected readonly WPos from, to;
|
||||
protected readonly int fromFacing, toFacing;
|
||||
protected readonly int moveFractionTotal;
|
||||
protected int moveFraction;
|
||||
|
||||
public MovePart(Move move, PPos from, PPos to, int fromFacing, int toFacing, int startingFraction)
|
||||
public MovePart(Move move, WPos from, WPos to, int fromFacing, int toFacing, int startingFraction)
|
||||
{
|
||||
this.move = move;
|
||||
this.from = from;
|
||||
@@ -286,7 +277,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
this.fromFacing = fromFacing;
|
||||
this.toFacing = toFacing;
|
||||
this.moveFraction = startingFraction;
|
||||
this.moveFractionTotal = 3*(to - from).Length;
|
||||
this.moveFractionTotal = (to - from).Length;
|
||||
}
|
||||
|
||||
public override void Cancel(Actor self)
|
||||
@@ -304,7 +295,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
var mobile = self.Trait<Mobile>();
|
||||
var ret = InnerTick(self, mobile);
|
||||
mobile.IsMoving = (ret is MovePart);
|
||||
mobile.IsMoving = ret is MovePart;
|
||||
|
||||
if (moveFraction > moveFractionTotal)
|
||||
moveFraction = moveFractionTotal;
|
||||
@@ -328,7 +319,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
|
||||
void UpdateCenterLocation(Actor self, Mobile mobile)
|
||||
{
|
||||
mobile.PxPosition = PPos.Lerp(from, to, moveFraction, moveFractionTotal);
|
||||
mobile.SetVisualPosition(self, WPos.Lerp(from, to, moveFraction, moveFractionTotal));
|
||||
|
||||
if (moveFraction >= moveFractionTotal)
|
||||
mobile.Facing = toFacing & 0xFF;
|
||||
@@ -346,7 +337,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
|
||||
class MoveFirstHalf : MovePart
|
||||
{
|
||||
public MoveFirstHalf(Move move, PPos from, PPos to, int fromFacing, int toFacing, int startingFraction)
|
||||
public MoveFirstHalf(Move move, WPos from, WPos to, int fromFacing, int toFacing, int startingFraction)
|
||||
: base(move, from, to, fromFacing, toFacing, startingFraction) { }
|
||||
|
||||
static bool IsTurn(Mobile mobile, CPos nextCell)
|
||||
@@ -372,8 +363,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
Util.BetweenCells(mobile.toCell, nextCell.Value.First) + (toSubcellOffset + nextSubcellOffset) / 2,
|
||||
mobile.Facing,
|
||||
Util.GetNearestFacing(mobile.Facing, Util.GetFacing(nextCell.Value.First - mobile.toCell, mobile.Facing)),
|
||||
moveFraction - moveFractionTotal
|
||||
);
|
||||
moveFraction - moveFractionTotal);
|
||||
|
||||
mobile.SetLocation(mobile.toCell, mobile.toSubCell, nextCell.Value.First, nextCell.Value.Second);
|
||||
return ret;
|
||||
@@ -385,11 +375,10 @@ namespace OpenRA.Mods.RA.Move
|
||||
var ret2 = new MoveSecondHalf(
|
||||
move,
|
||||
Util.BetweenCells(mobile.fromCell, mobile.toCell) + (fromSubcellOffset + toSubcellOffset) / 2,
|
||||
Util.CenterOfCell(mobile.toCell) + toSubcellOffset,
|
||||
mobile.toCell.CenterPosition + toSubcellOffset,
|
||||
mobile.Facing,
|
||||
mobile.Facing,
|
||||
moveFraction - moveFractionTotal
|
||||
);
|
||||
moveFraction - moveFractionTotal);
|
||||
|
||||
mobile.EnteringCell(self);
|
||||
mobile.SetLocation(mobile.toCell, mobile.toSubCell, mobile.toCell, mobile.toSubCell);
|
||||
@@ -399,14 +388,12 @@ namespace OpenRA.Mods.RA.Move
|
||||
|
||||
class MoveSecondHalf : MovePart
|
||||
{
|
||||
public MoveSecondHalf(Move move, PPos from, PPos to, int fromFacing, int toFacing, int startingFraction)
|
||||
: base(move, from, to, fromFacing, toFacing, startingFraction) {}
|
||||
public MoveSecondHalf(Move move, WPos from, WPos to, int fromFacing, int toFacing, int startingFraction)
|
||||
: base(move, from, to, fromFacing, toFacing, startingFraction) { }
|
||||
|
||||
protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent)
|
||||
{
|
||||
mobile.PxPosition = Util.CenterOfCell(mobile.toCell);
|
||||
mobile.SetLocation(mobile.toCell, mobile.toSubCell, mobile.toCell, mobile.toSubCell);
|
||||
mobile.FinishedMoving(self);
|
||||
mobile.SetPosition(self, mobile.toCell);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -416,12 +403,10 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
public static bool IsMoving(this Actor self)
|
||||
{
|
||||
if (self.IsIdle)
|
||||
var a = self.GetCurrentActivity();
|
||||
if (a == null)
|
||||
return false;
|
||||
|
||||
Activity a = self.GetCurrentActivity();
|
||||
Debug.Assert(a != null);
|
||||
|
||||
// Dirty, but it suffices until we do something better:
|
||||
if (a.GetType() == typeof(Move)) return true;
|
||||
if (a.GetType() == typeof(MoveAdjacentTo)) return true;
|
||||
|
||||
@@ -88,8 +88,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
var rangeSquared = range.Range*range.Range;
|
||||
|
||||
// Correct for SubCell offset
|
||||
var so = MobileInfo.SubCellOffsets[srcSub];
|
||||
target -= new WVec(so.X * 1024 / Game.CellSize, so.Y * 1024 / Game.CellSize, 0);
|
||||
target -= MobileInfo.SubCellOffsets[srcSub];
|
||||
|
||||
// Select only the tiles that are within range from the requested SubCell
|
||||
// This assumes that the SubCell does not change during the path traversal
|
||||
|
||||
@@ -460,6 +460,7 @@
|
||||
<Compile Include="Widgets\Logic\SimpleTooltipLogic.cs" />
|
||||
<Compile Include="World\DomainIndex.cs" />
|
||||
<Compile Include="MPStartUnits.cs" />
|
||||
<Compile Include="Orders\SetChronoTankDestination.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#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
|
||||
@@ -50,7 +50,7 @@ namespace OpenRA.Mods.RA.Orders
|
||||
if (!world.LocalPlayer.Shroud.IsExplored(xy))
|
||||
return "move-blocked";
|
||||
|
||||
var movement = self.TraitOrDefault<IMove>();
|
||||
var movement = self.TraitOrDefault<IPositionable>();
|
||||
return (movement.CanEnterCell(xy)) ? "chrono-target" : "move-blocked";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#region Copyright & License Information
|
||||
#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
|
||||
@@ -60,7 +60,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
bool IsSuitableCell(Actor actorToDrop, CPos p)
|
||||
{
|
||||
return actorToDrop.Trait<ITeleportable>().CanEnterCell(p);
|
||||
return actorToDrop.Trait<IPositionable>().CanEnterCell(p);
|
||||
}
|
||||
|
||||
void FinishedDropping(Actor self)
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace OpenRA.Mods.RA
|
||||
attackerStats.BuildingsKilled++;
|
||||
defenderStats.BuildingsDead++;
|
||||
}
|
||||
else if (self.HasTrait<IMove>())
|
||||
else if (self.HasTrait<IPositionable>())
|
||||
{
|
||||
attackerStats.UnitsKilled++;
|
||||
defenderStats.UnitsDead++;
|
||||
|
||||
@@ -31,13 +31,15 @@ namespace OpenRA.Mods.RA
|
||||
public class ExitInfo : TraitInfo<Exit>
|
||||
{
|
||||
public readonly int2 SpawnOffset = int2.Zero; // in px relative to CenterLocation
|
||||
public readonly int2 ExitCell = int2.Zero; // in cells relative to TopLeft
|
||||
public readonly int2 ExitCell = int2.Zero; // in cells relative to TopLeft
|
||||
public readonly int Facing = -1;
|
||||
|
||||
public PVecInt SpawnOffsetVector { get { return (PVecInt)SpawnOffset; } }
|
||||
// TODO: Push this conversion into the yaml
|
||||
public WVec SpawnOffsetVector { get { return new WVec(SpawnOffset.X, SpawnOffset.Y, 0) * 1024 / Game.CellSize; } }
|
||||
public CVec ExitCellVector { get { return (CVec)ExitCell; } }
|
||||
}
|
||||
public class Exit {}
|
||||
|
||||
public class Exit { }
|
||||
|
||||
public class Production
|
||||
{
|
||||
@@ -50,7 +52,7 @@ namespace OpenRA.Mods.RA
|
||||
public void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo)
|
||||
{
|
||||
var exit = self.Location + exitinfo.ExitCellVector;
|
||||
var spawn = (self.Trait<IHasLocation>().PxPosition + exitinfo.SpawnOffsetVector).ToWPos(0);
|
||||
var spawn = self.CenterPosition + exitinfo.SpawnOffsetVector;
|
||||
var to = exit.CenterPosition;
|
||||
|
||||
var fi = producee.Traits.Get<IFacingInfo>();
|
||||
@@ -65,8 +67,8 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
// TODO: Move this into an *Init
|
||||
// TODO: We should be adjusting the actual position for aircraft, not just visuals.
|
||||
var teleportable = newUnit.Trait<ITeleportable>();
|
||||
teleportable.AdjustPxPosition(newUnit, PPos.FromWPos(spawn));
|
||||
var teleportable = newUnit.Trait<IPositionable>();
|
||||
teleportable.SetVisualPosition(newUnit, spawn);
|
||||
|
||||
// TODO: Generalize this for non-mobile (e.g. aircraft) too
|
||||
// Remember to update the Enter activity too
|
||||
@@ -74,8 +76,8 @@ namespace OpenRA.Mods.RA
|
||||
if (mobile != null)
|
||||
{
|
||||
// Animate the spawn -> exit transition
|
||||
var speed = mobile.WorldMovementSpeedForCell(newUnit, exit);
|
||||
var length = speed > 0 ? (int)((to - spawn).Length * 3 / speed) : 0;
|
||||
var speed = mobile.MovementSpeedForCell(newUnit, exit);
|
||||
var length = speed > 0 ? (to - spawn).Length / speed : 0;
|
||||
newUnit.QueueActivity(new Drag(spawn, to, length));
|
||||
}
|
||||
|
||||
@@ -104,7 +106,7 @@ namespace OpenRA.Mods.RA
|
||||
var helicopter = newUnit.TraitOrDefault<Helicopter>();
|
||||
if (helicopter != null)
|
||||
{
|
||||
newUnit.QueueActivity(new HeliFly(Util.CenterOfCell(rp.rallyPoint)));
|
||||
newUnit.QueueActivity(new HeliFly(rp.rallyPoint));
|
||||
return rp.rallyPoint;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA.Render
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
var isFlying = self.Trait<IMove>().Altitude > 0 && !self.IsDead();
|
||||
var isFlying = self.CenterPosition.Z > 0 && !self.IsDead();
|
||||
if (isFlying ^ (rotorAnim.CurrentSequence.Name != "rotor"))
|
||||
return;
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Mods.RA.Air;
|
||||
using OpenRA.Mods.RA.Move;
|
||||
|
||||
namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
@@ -24,16 +23,17 @@ namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
public IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r)
|
||||
{
|
||||
var move = self.Trait<IMove>();
|
||||
var ios = self.Trait<IOccupySpace>();
|
||||
|
||||
/* rude hack */
|
||||
var visualOffset = ((move is Helicopter || move is Mobile) && move.Altitude > 0)
|
||||
var flying = ios.CenterPosition.Z > 0;
|
||||
var visualOffset = (ios is Helicopter && flying)
|
||||
? (int)Math.Abs((self.ActorID + Game.LocalTick) / 5 % 4 - 1) - 1 : 0;
|
||||
|
||||
var shadowSprites = r.Select(a => a.WithPalette(wr.Palette("shadow"))
|
||||
.WithPos(a.Pos - new WVec(0, 0, a.Pos.Z)).WithZOffset(a.ZOffset + a.Pos.Z));
|
||||
|
||||
var flyingSprites = (move.Altitude <= 0) ? r :
|
||||
var flyingSprites = !flying ? r :
|
||||
r.Select(a => a.WithPos(a.Pos - new WVec(0,0,43*visualOffset)));
|
||||
|
||||
return shadowSprites.Concat(flyingSprites);
|
||||
|
||||
@@ -449,6 +449,7 @@
|
||||
Armor:
|
||||
Type: Light
|
||||
Husk:
|
||||
AllowedTerrain: Clear, Rough, Road, Tiberium, BlueTiberium, Beach
|
||||
HiddenUnderFog:
|
||||
AppearsOnRadar:
|
||||
Burns:
|
||||
|
||||
@@ -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
|
||||
@@ -28,7 +28,7 @@
|
||||
Types: Vehicle
|
||||
MaxWeight: 1
|
||||
PipCount: 1
|
||||
minimalUnloadAltitude: 25
|
||||
MaximumUnloadAltitude: 800
|
||||
LeavesHusk:
|
||||
HuskActor: CARRYALL.Husk
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
Armor:
|
||||
Type: Light
|
||||
Husk:
|
||||
AllowedTerrain: Sand, Rock, Transition, Concrete, Spice, SpiceBlobs, Dune
|
||||
HiddenUnderFog:
|
||||
AppearsOnRadar:
|
||||
Burns:
|
||||
|
||||
@@ -373,6 +373,7 @@
|
||||
|
||||
^Husk:
|
||||
Husk:
|
||||
AllowedTerrain: Clear, Rough, Road, Ore, Gems, Beach
|
||||
RenderUnit:
|
||||
Health:
|
||||
HP: 140
|
||||
@@ -385,6 +386,7 @@
|
||||
Types:Husk
|
||||
BelowUnits:
|
||||
BodyOrientation:
|
||||
Chronoshiftable:
|
||||
|
||||
^HelicopterHusk:
|
||||
Inherits: ^Husk
|
||||
|
||||
Reference in New Issue
Block a user