Merge pull request #11426 from pchote/actorpreview-dynamic-facing

Support dynamic ActorPreview facings and creating previews from live actors.
This commit is contained in:
reaperrr
2016-06-20 14:38:11 +02:00
committed by GitHub
39 changed files with 382 additions and 150 deletions

View File

@@ -0,0 +1,47 @@
using System;
using OpenRA.Traits;
namespace OpenRA.Mods.Common
{
public class FacingInit : IActorInit<int>
{
[FieldFromYamlKey] readonly int value = 128;
public FacingInit() { }
public FacingInit(int init) { value = init; }
public int Value(World world) { return value; }
}
public class DynamicFacingInit : IActorInit<Func<int>>
{
readonly Func<int> func;
public DynamicFacingInit(Func<int> func) { this.func = func; }
public Func<int> Value(World world) { return func; }
}
public class SubCellInit : IActorInit<SubCell>
{
[FieldFromYamlKey] readonly int value = (int)SubCell.FullCell;
public SubCellInit() { }
public SubCellInit(int init) { value = init; }
public SubCellInit(SubCell init) { value = (int)init; }
public SubCell Value(World world) { return (SubCell)value; }
}
public class CenterPositionInit : IActorInit<WPos>
{
[FieldFromYamlKey] readonly WPos value = WPos.Zero;
public CenterPositionInit() { }
public CenterPositionInit(WPos init) { value = init; }
public WPos Value(World world) { return value; }
}
// Allows maps / transformations to specify the faction variant of an actor.
public class FactionInit : IActorInit<string>
{
[FieldFromYamlKey] public readonly string Faction;
public FactionInit() { }
public FactionInit(string faction) { Faction = faction; }
public string Value(World world) { return Faction; }
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
@@ -42,6 +43,45 @@ namespace OpenRA.Mods.Common.Graphics
public U Get<T, U>() where T : IActorInit<U> { return dict.Get<T>().Value(World); }
public bool Contains<T>() where T : IActorInit { return dict.Contains<T>(); }
public Func<WRot> GetOrientation()
{
var facingInfo = Actor.TraitInfoOrDefault<IFacingInfo>();
if (facingInfo == null)
return () => WRot.Zero;
// Dynamic facing takes priority
var dynamicInit = dict.GetOrDefault<DynamicFacingInit>();
if (dynamicInit != null)
{
// TODO: Account for terrain slope
var getFacing = dynamicInit.Value(null);
return () => WRot.FromFacing(getFacing());
}
// Fall back to initial actor facing if an Init isn't available
var facingInit = dict.GetOrDefault<FacingInit>();
var facing = facingInit != null ? facingInit.Value(null) : facingInfo.GetInitialFacing();
var orientation = WRot.FromFacing(facing);
return () => orientation;
}
public Func<int> GetFacing()
{
var facingInfo = Actor.TraitInfoOrDefault<IFacingInfo>();
if (facingInfo == null)
return () => 0;
// Dynamic facing takes priority
var dynamicInit = dict.GetOrDefault<DynamicFacingInit>();
if (dynamicInit != null)
return dynamicInit.Value(null);
// Fall back to initial actor facing if an Init isn't available
var facingInit = dict.GetOrDefault<FacingInit>();
var facing = facingInit != null ? facingInit.Value(null) : facingInfo.GetInitialFacing();
return () => facing;
}
public DamageState GetDamageState()
{
var health = dict.GetOrDefault<HealthInit>();

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
@@ -17,12 +18,12 @@ namespace OpenRA.Mods.Common.Graphics
public class SpriteActorPreview : IActorPreview
{
readonly Animation animation;
readonly WVec offset;
readonly int zOffset;
readonly Func<WVec> offset;
readonly Func<int> zOffset;
readonly PaletteReference pr;
readonly float scale;
public SpriteActorPreview(Animation animation, WVec offset, int zOffset, PaletteReference pr, float scale)
public SpriteActorPreview(Animation animation, Func<WVec> offset, Func<int> zOffset, PaletteReference pr, float scale)
{
this.animation = animation;
this.offset = offset;
@@ -35,7 +36,7 @@ namespace OpenRA.Mods.Common.Graphics
public IEnumerable<IRenderable> Render(WorldRenderer wr, WPos pos)
{
return animation.Render(pos, offset, zOffset, pr, scale);
return animation.Render(pos, offset(), zOffset(), pr, scale);
}
}
}

View File

@@ -196,6 +196,7 @@
<Compile Include="Lint\LintBuildablePrerequisites.cs" />
<Compile Include="Lint\LintExts.cs" />
<Compile Include="LoadScreens\ModChooserLoadScreen.cs" />
<Compile Include="ActorInitializer.cs" />
<Compile Include="ShroudExts.cs" />
<Compile Include="Orders\BeaconOrderGenerator.cs" />
<Compile Include="Orders\DeployOrderTargeter.cs" />

View File

@@ -88,7 +88,7 @@ namespace OpenRA.Mods.Common.Traits
}
public class Aircraft : ITick, ISync, IFacing, IPositionable, IMove, IIssueOrder, IResolveOrder, IOrderVoice, IDeathActorInitModifier,
INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing
INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing, IActorPreviewInitModifier
{
static readonly Pair<CPos, SubCell>[] NoCells = { };
@@ -660,5 +660,11 @@ namespace OpenRA.Mods.Common.Traits
{
UnReserve();
}
void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits)
{
if (!inits.Contains<DynamicFacingInit>() && !inits.Contains<FacingInit>())
inits.Add(new DynamicFacingInit(() => Facing));
}
}
}

View File

@@ -61,7 +61,7 @@ namespace OpenRA.Mods.Common.Traits
// Z-order is one set to the top of the footprint
var offset = map.CenterOfCell(cell) - map.CenterOfCell(location) - centerOffset;
yield return new SpriteActorPreview(anim, offset, -(offset.Y + centerOffset.Y + 512), p, rs.Scale);
yield return new SpriteActorPreview(anim, () => offset, () => -(offset.Y + centerOffset.Y + 512), p, rs.Scale);
}
}
}

View File

@@ -309,8 +309,10 @@ namespace OpenRA.Mods.Common.Traits
upgradeManager.RevokeUpgrade(self, u, this);
}
foreach (var npe in self.TraitsImplementing<INotifyPassengerEntered>())
npe.OnPassengerEntered(self, a);
// If not initialized then this will be notified in the first tick
if (initialized)
foreach (var npe in self.TraitsImplementing<INotifyPassengerEntered>())
npe.OnPassengerEntered(self, a);
var p = a.Trait<Passenger>();
p.Transport = self;

View File

@@ -319,7 +319,7 @@ namespace OpenRA.Mods.Common.Traits
}
public class Mobile : UpgradableTrait<MobileInfo>, IIssueOrder, IResolveOrder, IOrderVoice, IPositionable, IMove, IFacing, ISync,
IDeathActorInitModifier, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyBlockingMove
IDeathActorInitModifier, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyBlockingMove, IActorPreviewInitModifier
{
const int AverageTicksBeforePathing = 5;
const int SpreadTicksBeforePathing = 5;
@@ -716,6 +716,12 @@ namespace OpenRA.Mods.Common.Traits
}
}
void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits)
{
if (!inits.Contains<DynamicFacingInit>() && !inits.Contains<FacingInit>())
inits.Add(new DynamicFacingInit(() => facing));
}
class MoveOrderTargeter : IOrderTargeter
{
readonly Mobile mobile;

View File

@@ -83,7 +83,7 @@ namespace OpenRA.Mods.Common.Traits.Render
}
}
public class RenderSprites : IRender, ITick, INotifyOwnerChanged, INotifyEffectiveOwnerChanged
public class RenderSprites : IRender, ITick, INotifyOwnerChanged, INotifyEffectiveOwnerChanged, IActorPreviewInitModifier
{
class AnimationWrapper
{
@@ -231,5 +231,11 @@ namespace OpenRA.Mods.Common.Traits.Render
.Select(a => (a.Animation.Animation.Image.Size.XY * info.Scale).ToInt2())
.FirstOrDefault();
}
void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits)
{
if (!inits.Contains<FactionInit>())
inits.Add(new FactionInit(faction));
}
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
@@ -20,7 +21,7 @@ namespace OpenRA.Mods.Common.Traits.Render
public interface IRenderActorPreviewVoxelsInfo : ITraitInfo
{
IEnumerable<VoxelAnimation> RenderPreviewVoxels(
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p);
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p);
}
public class RenderVoxelsInfo : ITraitInfo, IRenderActorPreviewInfo, Requires<BodyOrientationInfo>
@@ -58,11 +59,8 @@ namespace OpenRA.Mods.Common.Traits.Render
body.QuantizedFacings;
var palette = init.WorldRenderer.Palette(Palette ?? PlayerPalette + ownerName);
var ifacing = init.Actor.TraitInfoOrDefault<IFacingInfo>();
var facing = ifacing != null ? init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : ifacing.GetInitialFacing() : 0;
var orientation = WRot.FromFacing(facing);
var components = init.Actor.TraitInfos<IRenderActorPreviewVoxelsInfo>()
.SelectMany(rvpi => rvpi.RenderPreviewVoxels(init, this, image, orientation, facings, palette))
.SelectMany(rvpi => rvpi.RenderPreviewVoxels(init, this, image, init.GetOrientation(), facings, palette))
.ToArray();
yield return new VoxelPreview(components, WVec.Zero, 0, Scale, LightPitch,

View File

@@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Traits.Render
{
var anim = new Animation(init.World, rs.Image, () => 0);
anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), IdleSequence));
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale);
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
@@ -22,13 +23,10 @@ namespace OpenRA.Mods.Common.Traits.Render
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
var ifacing = init.Actor.TraitInfoOrDefault<IFacingInfo>();
var facing = ifacing != null ? init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : ifacing.GetInitialFacing() : 0;
var anim = new Animation(init.World, image, () => facing);
var anim = new Animation(init.World, image, init.GetFacing());
anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence));
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale);
}
}

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var anim = new Animation(init.World, image);
anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence), () => 0);
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale);
}
string IWallConnectorInfo.GetWallConnectionType()

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
@@ -46,14 +47,28 @@ namespace OpenRA.Mods.Common.Traits.Render
if (Palette != null)
p = init.WorldRenderer.Palette(Palette);
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
var anim = new Animation(init.World, image, () => facing);
Func<int> facing;
if (init.Contains<DynamicFacingInit>())
facing = init.Get<DynamicFacingInit, Func<int>>();
else
{
var f = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
facing = () => f;
}
var anim = new Animation(init.World, image, facing);
anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence));
var orientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing)), facings);
var offset = body.LocalToWorld(Offset.Rotate(orientation));
yield return new SpriteActorPreview(anim, offset, offset.Y + offset.Z + 1, p, rs.Scale);
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
Func<WRot> orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings);
Func<WVec> offset = () => body.LocalToWorld(Offset.Rotate(orientation()));
Func<int> zOffset = () =>
{
var tmpOffset = offset();
return tmpOffset.Y + tmpOffset.Z + 1;
};
yield return new SpriteActorPreview(anim, offset, zOffset, p, rs.Scale);
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
@@ -31,14 +32,9 @@ namespace OpenRA.Mods.Common.Traits.Render
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
var facing = 0;
var ifacing = init.Actor.TraitInfoOrDefault<IFacingInfo>();
if (ifacing != null)
facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : ifacing.GetInitialFacing();
var anim = new Animation(init.World, image, () => facing);
var anim = new Animation(init.World, image, init.GetFacing());
anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), StandSequences.First()));
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale);
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
@@ -68,14 +69,28 @@ namespace OpenRA.Mods.Common.Traits.Render
if (Palette != null)
p = init.WorldRenderer.Palette(Palette);
Func<int> facing;
if (init.Contains<DynamicFacingInit>())
facing = init.Get<DynamicFacingInit, Func<int>>();
else
{
var f = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
facing = () => f;
}
var anim = new Animation(init.World, image);
anim.PlayThen(OpeningSequence, () => anim.PlayRepeating(Sequence));
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
var orientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing)), facings);
var offset = body.LocalToWorld(Offset.Rotate(orientation));
yield return new SpriteActorPreview(anim, offset, offset.Y + offset.Z + 1, p, rs.Scale);
Func<WRot> orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings);
Func<WVec> offset = () => body.LocalToWorld(Offset.Rotate(orientation()));
Func<int> zOffset = () =>
{
var tmpOffset = offset();
return tmpOffset.Y + tmpOffset.Z + 1;
};
yield return new SpriteActorPreview(anim, offset, zOffset, p, rs.Scale);
}
}

View File

@@ -31,7 +31,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var bi = init.Actor.TraitInfo<BuildingInfo>();
var offset = FootprintUtils.CenterOffset(init.World, bi).Y + 512; // Additional 512 units move from center -> top of cell
yield return new SpriteActorPreview(anim, WVec.Zero, offset, p, rs.Scale);
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => offset, p, rs.Scale);
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
@@ -46,10 +47,15 @@ namespace OpenRA.Mods.Common.Traits.Render
var anim = new Animation(init.World, image, () => t.InitialFacing);
anim.Play(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence));
var turretOrientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(t.InitialFacing)), facings);
var turretOffset = body.LocalToWorld(t.Offset.Rotate(turretOrientation));
var turretOrientation = body.QuantizeOrientation(WRot.FromFacing(t.InitialFacing), facings);
Func<WVec> turretOffset = () => body.LocalToWorld(t.Offset.Rotate(turretOrientation));
Func<int> zOffset = () =>
{
var tmpOffset = turretOffset();
return tmpOffset.Y + tmpOffset.Z;
};
yield return new SpriteActorPreview(anim, turretOffset, turretOffset.Y + turretOffset.Z, p, rs.Scale);
yield return new SpriteActorPreview(anim, turretOffset, zOffset, p, rs.Scale);
}
}

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var anim = new Animation(init.World, image);
anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence));
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale);
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
@@ -44,16 +45,20 @@ namespace OpenRA.Mods.Common.Traits.Render
var t = init.Actor.TraitInfos<TurretedInfo>()
.First(tt => tt.Turret == Turret);
var ifacing = init.Actor.TraitInfoOrDefault<IFacingInfo>();
var bodyFacing = ifacing != null ? init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : ifacing.GetInitialFacing() : 0;
var turretFacing = Turreted.GetInitialTurretFacing(init, t.InitialFacing, Turret);
var anim = new Animation(init.World, image, () => turretFacing);
var turretFacing = Turreted.TurretFacingFromInit(init, t.InitialFacing, Turret);
var anim = new Animation(init.World, image, turretFacing);
anim.Play(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence));
var orientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(bodyFacing)), facings);
var offset = body.LocalToWorld(t.Offset.Rotate(orientation));
yield return new SpriteActorPreview(anim, offset, -(offset.Y + offset.Z) + 1, p, rs.Scale);
Func<int> facing = init.GetFacing();
Func<WRot> orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings);
Func<WVec> offset = () => body.LocalToWorld(t.Offset.Rotate(orientation()));
Func<int> zOffset = () =>
{
var tmpOffset = offset();
return -(tmpOffset.Y + tmpOffset.Z) + 1;
};
yield return new SpriteActorPreview(anim, offset, zOffset, p, rs.Scale);
}
}

View File

@@ -32,7 +32,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var anim = new Animation(init.World, image, () => t.InitialFacing);
anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), wsb.Sequence));
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale);
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
@@ -30,7 +31,8 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithVoxelBarrel(init.Self, this); }
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p)
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
if (UpgradeMinEnabledLevel > 0)
yield break;
@@ -43,14 +45,14 @@ namespace OpenRA.Mods.Common.Traits.Render
var voxel = VoxelProvider.GetVoxel(image, Sequence);
var turretFacing = Turreted.GetInitialTurretFacing(init, t.InitialFacing, t.Turret);
var turretOrientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(turretFacing) - orientation.Yaw), facings);
var turretFacing = Turreted.TurretFacingFromInit(init, t.InitialFacing, t.Turret);
Func<WRot> turretOrientation = () => body.QuantizeOrientation(WRot.FromYaw(WAngle.FromFacing(turretFacing()) - orientation().Yaw), facings);
var quantizedTurret = body.QuantizeOrientation(turretOrientation, facings);
var quantizedBody = body.QuantizeOrientation(orientation, facings);
var barrelOffset = body.LocalToWorld((t.Offset + LocalOffset.Rotate(quantizedTurret)).Rotate(quantizedBody));
Func<WRot> quantizedTurret = () => body.QuantizeOrientation(turretOrientation(), facings);
Func<WRot> quantizedBody = () => body.QuantizeOrientation(orientation(), facings);
Func<WVec> barrelOffset = () => body.LocalToWorld((t.Offset + LocalOffset.Rotate(quantizedTurret())).Rotate(quantizedBody()));
yield return new VoxelAnimation(voxel, () => barrelOffset, () => new[] { turretOrientation, orientation },
yield return new VoxelAnimation(voxel, barrelOffset, () => new[] { turretOrientation(), orientation() },
() => false, () => 0);
}
}

View File

@@ -25,13 +25,13 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithVoxelBody(init.Self, this); }
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p)
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var voxel = VoxelProvider.GetVoxel(image, "idle");
var bodyOrientation = new[] { body.QuantizeOrientation(orientation, facings) };
yield return new VoxelAnimation(voxel, () => WVec.Zero,
() => bodyOrientation,
() => new[] { body.QuantizeOrientation(orientation(), facings) },
() => false, () => 0);
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
@@ -27,7 +28,8 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithVoxelTurret(init.Self, this); }
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p)
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
if (UpgradeMinEnabledLevel > 0)
yield break;
@@ -37,12 +39,12 @@ namespace OpenRA.Mods.Common.Traits.Render
.First(tt => tt.Turret == Turret);
var voxel = VoxelProvider.GetVoxel(image, Sequence);
var turretOffset = body.LocalToWorld(t.Offset.Rotate(orientation));
Func<WVec> turretOffset = () => body.LocalToWorld(t.Offset.Rotate(orientation()));
var turretFacing = Turreted.GetInitialTurretFacing(init, t.InitialFacing, Turret);
var turretBodyOrientation = new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(turretFacing) - orientation.Yaw);
var turretOrientation = new[] { turretBodyOrientation, body.QuantizeOrientation(orientation, facings) };
yield return new VoxelAnimation(voxel, () => turretOffset, () => turretOrientation, () => false, () => 0);
var turretFacing = Turreted.TurretFacingFromInit(init, t.InitialFacing, Turret);
Func<WRot> turretBodyOrientation = () => WRot.FromYaw(WAngle.FromFacing(turretFacing()) - orientation().Yaw);
yield return new VoxelAnimation(voxel, turretOffset,
() => new[] { turretBodyOrientation(), body.QuantizeOrientation(orientation(), facings) }, () => false, () => 0);
}
}

View File

@@ -72,7 +72,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var anim = new Animation(init.World, image, () => 0);
anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence), () => adjacent);
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale);
}
string IWallConnectorInfo.GetWallConnectionType()

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Traits;
@@ -64,8 +65,9 @@ namespace OpenRA.Mods.Common.Traits
var body = self.Trait<BodyOrientation>();
// TODO: Carry orientation over from the parent instead of just facing
var bodyFacing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
facing = WAngle.FromFacing(Turreted.GetInitialTurretFacing(init, 0));
var bodyFacing = init.Contains<DynamicFacingInit>() ? init.Get<DynamicFacingInit, Func<int>>()()
: init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
facing = WAngle.FromFacing(Turreted.TurretFacingFromInit(init, 0)());
// Calculate final position
var throwRotation = WRot.FromFacing(Game.CosmeticRandom.Next(1024));

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Primitives;
using OpenRA.Traits;
@@ -31,7 +32,7 @@ namespace OpenRA.Mods.Common.Traits
public virtual object Create(ActorInitializer init) { return new Turreted(init, this); }
}
public class Turreted : ITick, ISync, INotifyCreated, IDeathActorInitModifier
public class Turreted : ITick, ISync, INotifyCreated, IDeathActorInitModifier, IActorPreviewInitModifier
{
readonly TurretedInfo info;
AttackTurreted attack;
@@ -49,28 +50,44 @@ namespace OpenRA.Mods.Common.Traits
public WVec Offset { get { return info.Offset + localOffset; } }
public string Name { get { return info.Turret; } }
public static int GetInitialTurretFacing(IActorInitializer init, int def, string turret = null)
public static Func<int> TurretFacingFromInit(IActorInitializer init, int def, string turret = null)
{
if (turret != null && init.Contains<DynamicTurretFacingsInit>())
{
Func<int> facing;
if (init.Get<DynamicTurretFacingsInit, Dictionary<string, Func<int>>>().TryGetValue(turret, out facing))
return facing;
}
if (turret != null && init.Contains<TurretFacingsInit>())
{
int facing;
if (init.Get<TurretFacingsInit, Dictionary<string, int>>().TryGetValue(turret, out facing))
return facing;
return () => facing;
}
if (init.Contains<TurretFacingInit>())
return init.Get<TurretFacingInit, int>();
{
var facing = init.Get<TurretFacingInit, int>();
return () => facing;
}
if (init.Contains<DynamicFacingInit>())
return init.Get<DynamicFacingInit, Func<int>>();
if (init.Contains<FacingInit>())
return init.Get<FacingInit, int>();
{
var facing = init.Get<FacingInit, int>();
return () => facing;
}
return def;
return () => def;
}
public Turreted(ActorInitializer init, TurretedInfo info)
{
this.info = info;
TurretFacing = GetInitialTurretFacing(init, info.InitialFacing, info.Turret);
TurretFacing = TurretFacingFromInit(init, info.InitialFacing, info.Turret)();
}
public void Created(Actor self)
@@ -157,6 +174,28 @@ namespace OpenRA.Mods.Common.Traits
facings.Value(self.World).Add(Name, TurretFacing);
}
void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits)
{
var facings = inits.GetOrDefault<DynamicTurretFacingsInit>();
if (facings == null)
{
facings = new DynamicTurretFacingsInit();
inits.Add(facings);
}
Func<int> bodyFacing = () => facing.Facing;
var dynamicFacing = inits.GetOrDefault<DynamicFacingInit>();
var staticFacing = inits.GetOrDefault<FacingInit>();
if (dynamicFacing != null)
bodyFacing = dynamicFacing.Value(self.World);
else if (staticFacing != null)
bodyFacing = () => staticFacing.Value(self.World);
// Freeze the relative turret facing to its current value
var facingOffset = TurretFacing - bodyFacing();
facings.Value(self.World).Add(Name, () => bodyFacing() + facingOffset);
}
}
public class TurretFacingInit : IActorInit<int>
@@ -175,4 +214,12 @@ namespace OpenRA.Mods.Common.Traits
public TurretFacingsInit(Dictionary<string, int> init) { value = init; }
public Dictionary<string, int> Value(World world) { return value; }
}
public class DynamicTurretFacingsInit : IActorInit<Dictionary<string, Func<int>>>
{
readonly Dictionary<string, Func<int>> value = new Dictionary<string, Func<int>>();
public DynamicTurretFacingsInit() { }
public DynamicTurretFacingsInit(Dictionary<string, Func<int>> init) { value = init; }
public Dictionary<string, Func<int>> Value(World world) { return value; }
}
}

View File

@@ -125,4 +125,10 @@ namespace OpenRA.Mods.Common.Traits
bool AdjacentWallCanConnect(Actor self, CPos wallLocation, string wallType, out CVec facing);
void SetDirty();
}
[RequireExplicitImplementation]
public interface IActorPreviewInitModifier
{
void ModifyActorPreviewInit(Actor self, TypeDictionary inits);
}
}