Merge pull request #7638 from pchote/infantry-body

Decompose RenderInfantry into WithInfantryBody and RenderSprites.
This commit is contained in:
Oliver Brakmann
2015-03-21 15:22:53 +01:00
26 changed files with 292 additions and 207 deletions

View File

@@ -373,7 +373,6 @@
<Compile Include="Traits\Render\RenderEditorOnly.cs" />
<Compile Include="Traits\Render\RenderFlare.cs" />
<Compile Include="Traits\Render\RenderHarvester.cs" />
<Compile Include="Traits\Render\RenderInfantry.cs" />
<Compile Include="Traits\Render\RenderNameTag.cs" />
<Compile Include="Traits\Render\RenderSimple.cs" />
<Compile Include="Traits\Render\RenderSprites.cs" />
@@ -616,6 +615,7 @@
<Compile Include="Widgets\TooltipContainerWidget.cs" />
<Compile Include="Widgets\ViewportControllerWidget.cs" />
<Compile Include="Widgets\VqaPlayerWidget.cs" />
<Compile Include="Traits\Render\WithInfantryBody.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>

View File

@@ -148,7 +148,7 @@ namespace OpenRA.Mods.Common.Traits
return cachedImage = info.GetImage(self.Info, self.World.Map.SequenceProvider, race);
}
protected void UpdatePalette()
public void UpdatePalette()
{
foreach (var anim in anims.Values)
anim.OwnerChanged();

View File

@@ -14,7 +14,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("This actor has a death animation.")]
public class WithDeathAnimationInfo : ITraitInfo, Requires<RenderSimpleInfo>
public class WithDeathAnimationInfo : ITraitInfo, Requires<RenderSpritesInfo>
{
[Desc("Sequence to play when this actor is killed by a warhead.")]
public readonly string DeathSequence = "die";
@@ -35,12 +35,12 @@ namespace OpenRA.Mods.Common.Traits
public class WithDeathAnimation : INotifyKilled
{
public readonly WithDeathAnimationInfo Info;
readonly RenderSimple renderSimple;
readonly RenderSprites rs;
public WithDeathAnimation(Actor self, WithDeathAnimationInfo info)
{
Info = info;
renderSimple = self.Trait<RenderSimple>();
rs = self.Trait<RenderSprites>();
}
public void Killed(Actor self, AttackInfo e)
@@ -66,7 +66,7 @@ namespace OpenRA.Mods.Common.Traits
self.World.AddFrameEndTask(w =>
{
if (!self.Destroyed)
w.Add(new Corpse(w, self.CenterPosition, renderSimple.GetImage(self), sequence, palette));
w.Add(new Corpse(w, self.CenterPosition, rs.GetImage(self), sequence, palette));
});
}
}

View File

@@ -16,18 +16,18 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public class RenderInfantryInfo : RenderSimpleInfo, Requires<IMoveInfo>
public class WithInfantryBodyInfo : ITraitInfo, IQuantizeBodyOrientationInfo, IRenderActorPreviewSpritesInfo, Requires<IMoveInfo>, Requires<RenderSpritesInfo>
{
public readonly int MinIdleWaitTicks = 30;
public readonly int MaxIdleWaitTicks = 110;
public readonly string MoveAnimation = "run";
public readonly string AttackAnimation = "shoot";
public readonly string[] IdleAnimations = { };
public readonly string[] StandAnimations = { "stand" };
public readonly string MoveSequence = "run";
public readonly string AttackSequence = "shoot";
public readonly string[] IdleSequences = { };
public readonly string[] StandSequences = { "stand" };
public override object Create(ActorInitializer init) { return new RenderInfantry(init, this); }
public virtual object Create(ActorInitializer init) { return new WithInfantryBody(init, this); }
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
var facing = 0;
var ifacing = init.Actor.Traits.GetOrDefault<IFacingInfo>();
@@ -35,20 +35,23 @@ namespace OpenRA.Mods.Common.Traits
facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : ifacing.GetInitialFacing();
var anim = new Animation(init.World, image, () => facing);
anim.PlayRepeating(StandAnimations.First());
anim.PlayRepeating(StandSequences.First());
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
}
public override int QuantizedBodyFacings(ActorInfo ai, SequenceProvider sequenceProvider, string race)
public int QuantizedBodyFacings(ActorInfo ai, SequenceProvider sequenceProvider, string race)
{
return sequenceProvider.GetSequence(GetImage(ai, sequenceProvider, race), StandAnimations.First()).Facings;
var rsi = ai.Traits.Get<RenderSpritesInfo>();
return sequenceProvider.GetSequence(rsi.GetImage(ai, sequenceProvider, race), StandSequences.First()).Facings;
}
}
public class RenderInfantry : RenderSimple, INotifyAttack, INotifyIdle
public class WithInfantryBody : ITick, INotifyAttack, INotifyIdle
{
readonly RenderInfantryInfo info;
readonly WithInfantryBodyInfo info;
readonly IMove move;
protected readonly Animation DefaultAnimation;
bool dirty = false;
string idleSequence;
int idleDelay;
@@ -58,11 +61,16 @@ namespace OpenRA.Mods.Common.Traits
bool IsModifyingSequence { get { return rsm != null && rsm.IsModifyingSequence; } }
bool wasModifying;
public RenderInfantry(ActorInitializer init, RenderInfantryInfo info)
: base(init, info, MakeFacingFunc(init.Self))
public WithInfantryBody(ActorInitializer init, WithInfantryBodyInfo info)
{
this.info = info;
DefaultAnimation.PlayFetchIndex(NormalizeInfantrySequence(init.Self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
var self = init.Self;
var rs = self.Trait<RenderSprites>();
DefaultAnimation = new Animation(init.World, rs.GetImage(self), RenderSprites.MakeFacingFunc(self));
rs.Add("", DefaultAnimation);
DefaultAnimation.PlayFetchIndex(NormalizeInfantrySequence(init.Self, info.StandSequences.Random(Game.CosmeticRandom)), () => 0);
state = AnimationState.Waiting;
move = init.Self.Trait<IMove>();
rsm = init.Self.TraitOrDefault<IRenderInfantrySequenceModifier>();
@@ -86,8 +94,8 @@ namespace OpenRA.Mods.Common.Traits
public void Attacking(Actor self, Target target)
{
state = AnimationState.Attacking;
if (DefaultAnimation.HasSequence(NormalizeInfantrySequence(self, info.AttackAnimation)))
DefaultAnimation.PlayThen(NormalizeInfantrySequence(self, info.AttackAnimation), () => state = AnimationState.Idle);
if (DefaultAnimation.HasSequence(NormalizeInfantrySequence(self, info.AttackSequence)))
DefaultAnimation.PlayThen(NormalizeInfantrySequence(self, info.AttackSequence), () => state = AnimationState.Idle);
}
public void Attacking(Actor self, Target target, Armament a, Barrel barrel)
@@ -95,10 +103,8 @@ namespace OpenRA.Mods.Common.Traits
Attacking(self, target);
}
public override void Tick(Actor self)
public virtual void Tick(Actor self)
{
base.Tick(self);
if (rsm != null)
{
if (wasModifying != rsm.IsModifyingSequence)
@@ -110,12 +116,12 @@ namespace OpenRA.Mods.Common.Traits
if ((state == AnimationState.Moving || dirty) && !move.IsMoving)
{
state = AnimationState.Waiting;
DefaultAnimation.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
DefaultAnimation.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandSequences.Random(Game.CosmeticRandom)), () => 0);
}
else if ((state != AnimationState.Moving || dirty) && move.IsMoving)
{
state = AnimationState.Moving;
DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, info.MoveAnimation));
DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, info.MoveSequence));
}
dirty = false;
@@ -125,12 +131,12 @@ namespace OpenRA.Mods.Common.Traits
{
if (state != AnimationState.Idle && state != AnimationState.IdleAnimating)
{
DefaultAnimation.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
DefaultAnimation.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandSequences.Random(Game.CosmeticRandom)), () => 0);
state = AnimationState.Idle;
if (info.IdleAnimations.Length > 0)
if (info.IdleSequences.Length > 0)
{
idleSequence = info.IdleAnimations.Random(self.World.SharedRandom);
idleSequence = info.IdleSequences.Random(self.World.SharedRandom);
idleDelay = self.World.SharedRandom.Next(info.MinIdleWaitTicks, info.MaxIdleWaitTicks);
}
}
@@ -143,14 +149,14 @@ namespace OpenRA.Mods.Common.Traits
state = AnimationState.IdleAnimating;
DefaultAnimation.PlayThen(idleSequence, () =>
{
DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)));
DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, info.StandSequences.Random(Game.CosmeticRandom)));
state = AnimationState.Waiting;
});
}
}
else
{
DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)));
DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, info.StandSequences.Random(Game.CosmeticRandom)));
state = AnimationState.Waiting;
}
}

View File

@@ -719,6 +719,61 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
if (engineVersion < 20150321)
{
// Note: These rules are set up to do approximately the right thing for maps, but
// mods need additional manual tweaks. This is the best we can do without having
// much smarter rules parsing, because we currently can't reason about inherited traits.
if (depth == 0)
{
var childKeys = new[] { "MinIdleWaitTicks", "MaxIdleWaitTicks", "MoveAnimation", "AttackAnimation", "IdleAnimations", "StandAnimations" };
var ri = node.Value.Nodes.FirstOrDefault(n => n.Key.StartsWith("RenderInfantry"));
if (ri != null)
{
ri.Key = "WithInfantryBody";
var rsNodes = ri.Value.Nodes.Where(n => !childKeys.Contains(n.Key)).ToList();
if (rsNodes.Any())
node.Value.Nodes.Add(new MiniYamlNode("RenderSprites", new MiniYaml("", rsNodes)));
ri.Value.Nodes.RemoveAll(n => rsNodes.Contains(n));
}
var rri = node.Value.Nodes.FirstOrDefault(n => n.Key.StartsWith("-RenderInfantry"));
if (rri != null)
rri.Key = "-WithInfantryBody";
var rdi = node.Value.Nodes.FirstOrDefault(n => n.Key.StartsWith("RenderDisguise"));
if (rdi != null)
{
rdi.Key = "WithDisguisingInfantryBody";
var rsNodes = rdi.Value.Nodes.Where(n => !childKeys.Contains(n.Key)).ToList();
if (rsNodes.Any())
node.Value.Nodes.Add(new MiniYamlNode("RenderSprites", new MiniYaml("", rsNodes)));
rdi.Value.Nodes.RemoveAll(n => rsNodes.Contains(n));
}
var rrdi = node.Value.Nodes.FirstOrDefault(n => n.Key.StartsWith("-RenderDisguise"));
if (rrdi != null)
rrdi.Key = "-WithDisguisingInfantryBody";
}
if (depth == 2 && node.Key == "MoveAnimation")
node.Key = "MoveSequence";
if (depth == 2 && node.Key == "AttackAnimation")
node.Key = "AttackSequence";
if (depth == 2 && node.Key == "IdleAnimations")
node.Key = "IdleSequences";
if (depth == 2 && node.Key == "StandAnimations")
node.Key = "StandSequences";
}
UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1);
}
}