Convert turret facings to WAngle relative to the body.

This commit is contained in:
Paul Chote
2020-07-18 12:41:22 +01:00
committed by reaperrr
parent 70a86bed7a
commit 75cb5c2166
15 changed files with 189 additions and 192 deletions

View File

@@ -76,19 +76,12 @@ namespace OpenRA.Mods.Cnc.Traits
{
state = PopupState.Closed;
wsb.PlayCustomAnimationRepeating(self, info.ClosedIdleSequence);
turret.DesiredFacing = null;
turret.FaceTarget(self, Target.Invalid);
}
}
protected override bool CanAttack(Actor self, Target target)
{
if (state == PopupState.Transitioning)
return false;
if (!base.CanAttack(self, target))
return false;
idleTicks = 0;
if (state == PopupState.Closed)
{
state = PopupState.Transitioning;
@@ -97,9 +90,14 @@ namespace OpenRA.Mods.Cnc.Traits
state = PopupState.Open;
wsb.PlayCustomAnimationRepeating(self, wsb.Info.Sequence);
});
return false;
idleTicks = 0;
}
if (state == PopupState.Transitioning || !base.CanAttack(self, target))
return false;
idleTicks = 0;
return true;
}
@@ -107,17 +105,18 @@ namespace OpenRA.Mods.Cnc.Traits
{
if (state == PopupState.Open && idleTicks++ > info.CloseDelay)
{
turret.DesiredFacing = info.DefaultFacing.Facing;
var facingOffset = new WVec(0, -1024, 0).Rotate(WRot.FromYaw(info.DefaultFacing));
turret.FaceTarget(self, Target.FromPos(self.CenterPosition + facingOffset));
state = PopupState.Rotating;
}
else if (state == PopupState.Rotating && turret.TurretFacing == info.DefaultFacing.Facing)
else if (state == PopupState.Rotating && turret.HasAchievedDesiredFacing)
{
state = PopupState.Transitioning;
wsb.PlayCustomAnimation(self, info.ClosingSequence, () =>
{
state = PopupState.Closed;
wsb.PlayCustomAnimationRepeating(self, info.ClosedIdleSequence);
turret.DesiredFacing = null;
turret.FaceTarget(self, Target.Invalid);
});
}
}

View File

@@ -34,7 +34,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render
var wsb = init.Actor.TraitInfos<WithSpriteBodyInfo>().FirstOrDefault();
// Show the correct turret facing
var anim = new Animation(init.World, image, Turreted.TurretFacingFromInit(init, t));
var anim = new Animation(init.World, image, t.WorldFacingFromInit(init));
anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), wsb.Sequence));
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale);
@@ -49,7 +49,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render
{
// Turret artwork is baked into the sprite, so only the first turret makes sense.
var turreted = self.TraitsImplementing<Turreted>().FirstOrDefault();
return () => WAngle.FromFacing(turreted.TurretFacing);
return () => turreted.WorldOrientation.Yaw;
}
public WithEmbeddedTurretSpriteBody(ActorInitializer init, WithSpriteBodyInfo info)

View File

@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render
{
// Turret artwork is baked into the sprite, so only the first turret makes sense.
var turreted = self.TraitsImplementing<Turreted>().FirstOrDefault();
return () => WAngle.FromFacing(turreted.TurretFacing);
return () => turreted.WorldOrientation.Yaw;
}
public WithGunboatBody(ActorInitializer init, WithGunboatBodyInfo info)

View File

@@ -84,15 +84,7 @@ namespace OpenRA.Mods.Common.Activities
var targetPosition = self.CenterPosition + body.LocalToWorld(localOffset);
var targetLocation = self.World.Map.CellContaining(targetPosition);
carryall.Carryable.Trait<IPositionable>().SetPosition(carryall.Carryable, targetLocation, SubCell.FullCell);
// HACK: directly manipulate the turret facings to match the new orientation
// This can eventually go away, when we make turret facings relative to the body
var carryableFacing = carryall.Carryable.Trait<IFacing>();
var facingDelta = facing.Facing - carryableFacing.Facing;
foreach (var t in carryall.Carryable.TraitsImplementing<Turreted>())
t.TurretFacing += facingDelta.Facing;
carryableFacing.Facing = facing.Facing;
carryall.Carryable.Trait<IFacing>().Facing = facing.Facing;
// Put back into world
self.World.AddFrameEndTask(w =>

View File

@@ -374,19 +374,18 @@ namespace OpenRA.Mods.Common.Traits
protected virtual WVec CalculateMuzzleOffset(Actor self, Barrel b)
{
var bodyOrientation = coords.QuantizeOrientation(self, self.Orientation);
// Weapon offset in turret coordinates
var localOffset = b.Offset + new WVec(-Recoil, WDist.Zero, WDist.Zero);
if (turret != null)
{
// WorldOrientation is quantized to satisfy the *Fudges.
// Need to then convert back to a pseudo-local coordinate space, apply offsets,
// then rotate back at the end
var turretOrientation = turret.WorldOrientation(self) - bodyOrientation;
localOffset = localOffset.Rotate(turretOrientation);
localOffset += turret.Offset;
}
return coords.LocalToWorld(localOffset.Rotate(bodyOrientation));
// Turret coordinates to body coordinates
var bodyOrientation = coords.QuantizeOrientation(self, self.Orientation);
if (turret != null)
localOffset = localOffset.Rotate(turret.WorldOrientation) + turret.Offset.Rotate(bodyOrientation);
else
localOffset = localOffset.Rotate(bodyOrientation);
// Body coordinates to world coordinates
return coords.LocalToWorld(localOffset);
}
public WRot MuzzleOrientation(Actor self, Barrel b)
@@ -396,10 +395,7 @@ namespace OpenRA.Mods.Common.Traits
protected virtual WRot CalculateMuzzleOrientation(Actor self, Barrel b)
{
var orientation = turret != null ? turret.WorldOrientation(self) :
coords.QuantizeOrientation(self, self.Orientation);
return orientation + WRot.FromYaw(b.Yaw);
return WRot.FromYaw(b.Yaw).Rotate(turret != null ? turret.WorldOrientation : self.Orientation);
}
public Actor Actor { get { return self; } }

View File

@@ -371,9 +371,6 @@ namespace OpenRA.Mods.Common.Traits
var passengerFacing = passenger.TraitOrDefault<IFacing>();
if (passengerFacing != null)
passengerFacing.Facing = facing.Value.Facing + Info.PassengerFacing;
foreach (var t in passenger.TraitsImplementing<Turreted>())
t.TurretFacing = (facing.Value.Facing + Info.PassengerFacing).Facing;
}
public void Load(Actor self, Actor a)

View File

@@ -110,9 +110,15 @@ namespace OpenRA.Mods.Common.Traits
foreach (var b in a.Barrels)
{
var barrelEnd = new Barrel
{
Offset = b.Offset + new WVec(224, 0, 0),
Yaw = b.Yaw
};
var muzzle = self.CenterPosition + a.MuzzleOffset(self, b);
var dirOffset = new WVec(0, -224, 0).Rotate(a.MuzzleOrientation(self, b));
yield return new LineAnnotationRenderable(muzzle, muzzle + dirOffset, 1, Color.White);
var endMuzzle = self.CenterPosition + a.MuzzleOffset(self, barrelEnd);
yield return new LineAnnotationRenderable(muzzle, endMuzzle, 1, Color.White);
}
}
}

View File

@@ -110,11 +110,7 @@ namespace OpenRA.Mods.Common.Traits
if (turret != null)
{
// WorldOrientation is quantized to satisfy the *Fudges.
// Need to then convert back to a pseudo-local coordinate space, apply offsets,
// then rotate back at the end
var turretOrientation = turret.WorldOrientation(self) - quantizedBodyOrientation;
localOffset = localOffset.Rotate(turretOrientation);
localOffset = localOffset.Rotate(turret.LocalOrientation);
localOffset += turret.Offset;
}
@@ -123,27 +119,15 @@ namespace OpenRA.Mods.Common.Traits
public WDist DistanceFromEdge(Actor self, WPos pos)
{
var origin = self.CenterPosition;
var orientation = self.Orientation;
if (turret != null)
{
origin += turret.Position(self);
orientation = turret.WorldOrientation(self);
}
var origin = turret != null ? self.CenterPosition + turret.Position(self) : self.CenterPosition;
var orientation = turret != null ? turret.WorldOrientation : self.Orientation;
return Info.Type.DistanceFromEdge(pos, origin, orientation);
}
public IEnumerable<IRenderable> RenderDebugOverlay(Actor self, WorldRenderer wr)
{
var origin = self.CenterPosition;
var orientation = self.Orientation;
if (turret != null)
{
origin += turret.Position(self);
orientation = turret.WorldOrientation(self);
}
var origin = turret != null ? self.CenterPosition + turret.Position(self) : self.CenterPosition;
var orientation = turret != null ? turret.WorldOrientation : self.Orientation;
return Info.Type.RenderDebugOverlay(wr, origin, orientation);
}
}

View File

@@ -52,10 +52,8 @@ namespace OpenRA.Mods.Common.Traits.Render
var turreted = self.TraitsImplementing<Turreted>()
.FirstOrDefault(t => t.Name == arm.Info.Turret);
// Workaround for broken ternary operators in certain versions of mono (3.10 and
// certain versions of the 3.8 series): https://bugzilla.xamarin.com/show_bug.cgi?id=23319
if (turreted != null)
getFacing = () => WAngle.FromFacing(turreted.TurretFacing);
getFacing = () => turreted.WorldOrientation.Yaw;
else if (facing != null)
getFacing = () => facing.Facing;
else

View File

@@ -45,7 +45,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var t = init.Actor.TraitInfos<TurretedInfo>()
.First(tt => tt.Turret == armament.Turret);
var turretFacing = Turreted.TurretFacingFromInit(init, t);
var turretFacing = t.WorldFacingFromInit(init);
var anim = new Animation(init.World, image, turretFacing);
anim.Play(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence));
@@ -82,7 +82,7 @@ namespace OpenRA.Mods.Common.Traits.Render
.First(tt => tt.Name == armament.Info.Turret);
rs = self.Trait<RenderSprites>();
DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => WAngle.FromFacing(turreted.TurretFacing));
DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => turreted.WorldOrientation.Yaw);
DefaultAnimation.PlayRepeating(NormalizeSequence(self, Info.Sequence));
rs.Add(new AnimationWithOffset(
DefaultAnimation, () => BarrelOffset(), () => IsTraitDisabled, p => RenderUtils.ZOffsetFromCenter(self, p, 0)));
@@ -98,21 +98,10 @@ namespace OpenRA.Mods.Common.Traits.Render
WVec BarrelOffset()
{
var orientation = turreted != null ? turreted.WorldOrientation : self.Orientation;
var localOffset = Info.LocalOffset + new WVec(-armament.Recoil, WDist.Zero, WDist.Zero);
var turretOffset = turreted != null ? turreted.Position(self) : WVec.Zero;
var quantizedBody = body.QuantizeOrientation(self, self.Orientation);
var turretOrientation = turreted != null ? turreted.WorldOrientation(self) - quantizedBody : WRot.None;
var quantizedTurret = body.QuantizeOrientation(self, turretOrientation);
return turretOffset + body.LocalToWorld(localOffset.Rotate(quantizedTurret).Rotate(quantizedBody));
}
IEnumerable<WRot> BarrelRotation()
{
var b = self.Orientation;
var qb = body.QuantizeOrientation(self, b);
yield return turreted.WorldOrientation(self) - qb + WRot.FromYaw(b.Yaw - qb.Yaw);
yield return qb;
var turretLocalOffset = turreted != null ? turreted.Offset : WVec.Zero;
return body.LocalToWorld(turretLocalOffset + localOffset.Rotate(orientation));
}
}
}

View File

@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var t = init.Actor.TraitInfos<TurretedInfo>()
.First(tt => tt.Turret == Turret);
var turretFacing = Turreted.TurretFacingFromInit(init, t);
var turretFacing = t.WorldFacingFromInit(init);
var anim = new Animation(init.World, image, turretFacing);
anim.Play(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence));
@@ -90,7 +90,7 @@ namespace OpenRA.Mods.Common.Traits.Render
arms = self.TraitsImplementing<Armament>()
.Where(w => w.Info.Turret == info.Turret).ToArray();
DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => WAngle.FromFacing(t.TurretFacing));
DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => t.WorldOrientation.Yaw);
DefaultAnimation.PlayRepeating(NormalizeSequence(self, info.Sequence));
rs.Add(new AnimationWithOffset(DefaultAnimation,
() => TurretOffset(self),
@@ -106,10 +106,9 @@ namespace OpenRA.Mods.Common.Traits.Render
if (!Info.Recoils)
return t.Position(self);
var recoil = arms.Aggregate(WDist.Zero, (a, b) => a + b.Recoil);
var localOffset = new WVec(-recoil, WDist.Zero, WDist.Zero);
var quantizedWorldTurret = t.WorldOrientation(self);
return t.Position(self) + body.LocalToWorld(localOffset.Rotate(quantizedWorldTurret));
var recoilDist = arms.Aggregate(WDist.Zero, (a, b) => a + b.Recoil);
var recoil = new WVec(-recoilDist, WDist.Zero, WDist.Zero);
return t.Position(self) + body.LocalToWorld(recoil.Rotate(t.WorldOrientation));
}
public string NormalizeSequence(Actor self, string sequence)

View File

@@ -51,13 +51,11 @@ namespace OpenRA.Mods.Common.Traits.Render
var model = init.World.ModelCache.GetModelSequence(image, Sequence);
var turretFacing = Turreted.TurretFacingFromInit(init, t);
Func<WRot> turretOrientation = () => body.QuantizeOrientation(WRot.FromYaw(turretFacing() - orientation().Yaw), facings);
Func<WRot> quantizedTurret = () => body.QuantizeOrientation(turretOrientation(), facings);
var turretOrientation = t.PreviewOrientation(init, orientation, facings);
Func<WRot> quantizedBody = () => body.QuantizeOrientation(orientation(), facings);
Func<WVec> barrelOffset = () => body.LocalToWorld((t.Offset + LocalOffset.Rotate(quantizedTurret())).Rotate(quantizedBody()));
Func<WRot> barrelOrientation = () => turretOrientation().Rotate(orientation());
Func<WVec> barrelOffset = () => body.LocalToWorld((t.Offset + LocalOffset.Rotate(turretOrientation())).Rotate(quantizedBody()));
Func<WRot> barrelOrientation = () => LocalOrientation.Rotate(turretOrientation()).Rotate(quantizedBody());
yield return new ModelAnimation(model, barrelOffset, barrelOrientation, () => false, () => 0, ShowShadow);
}
}
@@ -87,21 +85,15 @@ namespace OpenRA.Mods.Common.Traits.Render
WVec BarrelOffset()
{
var b = self.Orientation;
var qb = body.QuantizeOrientation(self, b);
var orientation = turreted != null ? turreted.WorldOrientation : self.Orientation;
var localOffset = Info.LocalOffset + new WVec(-armament.Recoil, WDist.Zero, WDist.Zero);
var turretLocalOffset = turreted != null ? turreted.Offset : WVec.Zero;
var turretOrientation = turreted != null ? turreted.WorldOrientation(self) - b + WRot.FromYaw(b.Yaw - qb.Yaw) : WRot.None;
return body.LocalToWorld((turretLocalOffset + localOffset.Rotate(turretOrientation)).Rotate(qb));
return body.LocalToWorld(turretLocalOffset + localOffset.Rotate(orientation));
}
WRot BarrelRotation()
{
var b = self.Orientation;
var qb = body.QuantizeOrientation(self, b);
var t = turreted.WorldOrientation(self) - b + WRot.FromYaw(b.Yaw - qb.Yaw);
return Info.LocalOrientation.Rotate(t).Rotate(qb);
return Info.LocalOrientation.Rotate(turreted != null ? turreted.WorldOrientation : self.Orientation);
}
}
}

View File

@@ -37,17 +37,12 @@ namespace OpenRA.Mods.Common.Traits.Render
if (!EnabledByDefault)
yield break;
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var t = init.Actor.TraitInfos<TurretedInfo>()
.First(tt => tt.Turret == Turret);
var model = init.World.ModelCache.GetModelSequence(image, Sequence);
Func<WVec> turretOffset = () => body.LocalToWorld(t.Offset.Rotate(orientation()));
var turretFacing = Turreted.TurretFacingFromInit(init, t);
Func<WRot> turretOrientation = () => WRot.FromYaw(turretFacing() - orientation().Yaw)
.Rotate(body.QuantizeOrientation(orientation(), facings));
var turretOffset = t.PreviewPosition(init, orientation);
var turretOrientation = t.PreviewOrientation(init, orientation, facings);
yield return new ModelAnimation(model, turretOffset, turretOrientation, () => false, () => 0, ShowShadow);
}
}
@@ -68,15 +63,8 @@ namespace OpenRA.Mods.Common.Traits.Render
var rv = self.Trait<RenderVoxels>();
rv.Add(new ModelAnimation(self.World.ModelCache.GetModelSequence(rv.Image, Info.Sequence),
() => turreted.Position(self), TurretRotation,
() => turreted.Position(self), () => turreted.WorldOrientation,
() => IsTraitDisabled, () => 0, info.ShowShadow));
}
WRot TurretRotation()
{
var b = self.Orientation;
var qb = body.QuantizeOrientation(self, b);
return (turreted.WorldOrientation(self) - b + WRot.FromYaw(b.Yaw - qb.Yaw)).Rotate(qb);
}
}
}

View File

@@ -68,7 +68,7 @@ namespace OpenRA.Mods.Common.Traits
// TODO: Carry orientation over from the parent instead of just facing
var dynamicFacingInit = init.GetOrDefault<DynamicFacingInit>();
var bodyFacing = dynamicFacingInit != null ? dynamicFacingInit.Value() : init.GetValue<FacingInit, WAngle>(WAngle.Zero);
facing = Turreted.TurretFacingFromInit(init, info, WAngle.Zero)();
facing = TurretedInfo.WorldFacingFromInit(init, info, WAngle.Zero)();
// Calculate final position
var throwRotation = WRot.FromYaw(new WAngle(Game.CosmeticRandom.Next(1024)));

View File

@@ -12,6 +12,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Primitives;
using OpenRA.Traits;
@@ -54,36 +55,7 @@ namespace OpenRA.Mods.Common.Traits
(actor, value) => actor.ReplaceInit(new TurretFacingInit(this, new WAngle((int)value)), this));
}
public override object Create(ActorInitializer init) { return new Turreted(init, this); }
}
public class Turreted : PausableConditionalTrait<TurretedInfo>, ITick, IDeathActorInitModifier, IActorPreviewInitModifier
{
AttackTurreted attack;
IFacing facing;
BodyOrientation body;
[Sync]
public int QuantizedFacings = 0;
[Sync]
public int TurretFacing = 0;
public int? DesiredFacing;
int realignTick = 0;
// For subclasses that want to move the turret relative to the body
protected WVec localOffset = WVec.Zero;
public WVec Offset { get { return Info.Offset + localOffset; } }
public string Name { get { return Info.Turret; } }
public static Func<WAngle> TurretFacingFromInit(IActorInitializer init, TurretedInfo info)
{
return TurretFacingFromInit(init, info, info.InitialFacing);
}
public static Func<WAngle> TurretFacingFromInit(IActorInitializer init, TraitInfo info, WAngle defaultFacing)
public static Func<WAngle> WorldFacingFromInit(IActorInitializer init, TraitInfo info, WAngle defaultFacing)
{
// (Dynamic)TurretFacingInit is specified relative to the actor body.
// We need to add the body facing to return an absolute world angle.
@@ -102,17 +74,97 @@ namespace OpenRA.Mods.Common.Traits
return bodyFacing != null ? (Func<WAngle>)(() => bodyFacing() + facing) : () => facing;
}
var dynamicFacingInit = init.GetOrDefault<DynamicFacingInit>();
var dynamicFacingInit = init.GetOrDefault<DynamicTurretFacingInit>(info);
if (dynamicFacingInit != null)
return bodyFacing != null ? () => bodyFacing() + dynamicFacingInit.Value() : dynamicFacingInit.Value;
return bodyFacing ?? (Func<WAngle>)(() => defaultFacing);
return bodyFacing ?? (() => defaultFacing);
}
public Func<WAngle> WorldFacingFromInit(IActorInitializer init)
{
return WorldFacingFromInit(init, this, InitialFacing);
}
public Func<WAngle> LocalFacingFromInit(IActorInitializer init)
{
var turretFacingInit = init.GetOrDefault<TurretFacingInit>(this);
if (turretFacingInit != null)
{
var facing = turretFacingInit.Value;
return () => facing;
}
var dynamicFacingInit = init.GetOrDefault<DynamicTurretFacingInit>(this);
if (dynamicFacingInit != null)
return dynamicFacingInit.Value;
return () => InitialFacing;
}
// Turret offset in world-space
public Func<WVec> PreviewPosition(ActorPreviewInitializer init, Func<WRot> orientation)
{
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
return () => body.LocalToWorld(Offset.Rotate(orientation()));
}
// Orientation in world-space
public Func<WRot> PreviewOrientation(ActorPreviewInitializer init, Func<WRot> orientation, int facings)
{
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var turretFacing = LocalFacingFromInit(init);
Func<WRot> world = () => WRot.FromYaw(turretFacing()).Rotate(orientation());
if (facings == 0)
return world;
// Quantize orientation to match a rendered sprite
// Implies no pitch or roll
return () => WRot.FromYaw(body.QuantizeFacing(world().Yaw, facings));
}
public override object Create(ActorInitializer init) { return new Turreted(init, this); }
}
public class Turreted : PausableConditionalTrait<TurretedInfo>, ITick, IDeathActorInitModifier, IActorPreviewInitModifier
{
AttackTurreted attack;
IFacing facing;
BodyOrientation body;
[Sync]
public int QuantizedFacings = 0;
WVec? desiredDirection = null;
int realignTick = 0;
public WRot WorldOrientation
{
get
{
var world = facing != null ? LocalOrientation.Rotate(facing.Orientation) : LocalOrientation;
if (QuantizedFacings == 0)
return world;
// Quantize orientation to match a rendered sprite
// Implies no pitch or roll
return WRot.FromYaw(body.QuantizeFacing(world.Yaw, QuantizedFacings));
}
}
public WRot LocalOrientation { get; private set; }
// For subclasses that want to move the turret relative to the body
protected WVec localOffset = WVec.Zero;
public WVec Offset { get { return Info.Offset + localOffset; } }
public string Name { get { return Info.Turret; } }
public Turreted(ActorInitializer init, TurretedInfo info)
: base(info)
{
TurretFacing = TurretFacingFromInit(init, Info)().Facing;
LocalOrientation = WRot.FromYaw(info.LocalFacingFromInit(init)());
}
protected override void Created(Actor self)
@@ -143,7 +195,7 @@ namespace OpenRA.Mods.Common.Traits
if (realignTick < Info.RealignDelay)
realignTick++;
else if (Info.RealignDelay > -1)
DesiredFacing = null;
desiredDirection = null;
MoveTurret();
}
@@ -154,10 +206,33 @@ namespace OpenRA.Mods.Common.Traits
}
}
WAngle? DesiredLocalFacing
{
get
{
// A null value means we don't have a target
if (!desiredDirection.HasValue)
return null;
// A zero value means that we have a target, but it is on top of us
if (desiredDirection.Value == WVec.Zero)
return LocalOrientation.Yaw;
// PERF: If the turret rotation axis is vertical we can directly take the difference in facing/yaw
var o = facing != null ? facing.Orientation : (WRot?)null;
if (o == null || (o.Value.Pitch == WAngle.Zero && o.Value.Roll == WAngle.Zero))
return o.HasValue ? desiredDirection.Value.Yaw - o.Value.Yaw : desiredDirection.Value.Yaw;
// If the turret rotation axis is not vertical we must transform the
// target direction into the turrets local coordinate system
return desiredDirection.Value.Rotate(-o.Value).Yaw;
}
}
void MoveTurret()
{
var df = DesiredFacing ?? (facing != null ? facing.Facing.Facing : TurretFacing);
TurretFacing = Util.TickFacing(TurretFacing, df, Info.TurnSpeed.Facing);
var desired = DesiredLocalFacing ?? Info.InitialFacing;
LocalOrientation = LocalOrientation.WithYaw(Util.TickFacing(LocalOrientation.Yaw, desired, Info.TurnSpeed));
}
public bool FaceTarget(Actor self, Target target)
@@ -165,17 +240,27 @@ namespace OpenRA.Mods.Common.Traits
if (IsTraitDisabled || IsTraitPaused || attack == null || attack.IsTraitDisabled || attack.IsTraitPaused)
return false;
var pos = self.CenterPosition;
var targetPos = attack.GetTargetPosition(pos, target);
var delta = targetPos - pos;
DesiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : TurretFacing;
if (target.Type == TargetType.Invalid)
{
desiredDirection = null;
return false;
}
var turretPos = self.CenterPosition + Position(self);
var targetPos = attack.GetTargetPosition(turretPos, target);
desiredDirection = targetPos - turretPos;
MoveTurret();
return HasAchievedDesiredFacing;
}
public virtual bool HasAchievedDesiredFacing
{
get { return DesiredFacing == null || TurretFacing == DesiredFacing.Value; }
get
{
var desired = DesiredLocalFacing;
return !desired.HasValue || desired.Value == LocalOrientation.Yaw;
}
}
// Turret offset in world-space
@@ -185,42 +270,14 @@ namespace OpenRA.Mods.Common.Traits
return body.LocalToWorld(Offset.Rotate(bodyOrientation));
}
// Orientation in world-space
public WRot WorldOrientation(Actor self)
{
// Hack: turretFacing is relative to the world, so subtract the body yaw
var world = WRot.FromYaw(WAngle.FromFacing(TurretFacing));
if (QuantizedFacings == 0)
return world;
// Quantize orientation to match a rendered sprite
// Implies no pitch or yaw
return WRot.FromYaw(body.QuantizeFacing(world.Yaw, QuantizedFacings));
}
public void ModifyDeathActorInit(Actor self, TypeDictionary init)
{
var turretFacing = WAngle.FromFacing(TurretFacing);
if (facing != null)
turretFacing -= facing.Facing;
init.Add(new TurretFacingInit(Info, turretFacing));
init.Add(new TurretFacingInit(Info, LocalOrientation.Yaw));
}
void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits)
{
Func<WAngle> bodyFacing = () => facing.Facing;
var dynamicFacing = inits.GetOrDefault<DynamicFacingInit>();
var staticFacing = inits.GetOrDefault<FacingInit>();
if (dynamicFacing != null)
bodyFacing = dynamicFacing.Value;
else if (staticFacing != null)
bodyFacing = () => staticFacing.Value;
// Freeze the relative turret facing to its current value
var facingOffset = WAngle.FromFacing(TurretFacing) - bodyFacing();
inits.Add(new DynamicTurretFacingInit(Info, () => bodyFacing() + facingOffset));
inits.Add(new DynamicTurretFacingInit(Info, () => LocalOrientation.Yaw));
}
protected override void TraitDisabled(Actor self)