Fix GrantConditionOnDeploy to support multiple sprite bodies

This commit is contained in:
reaperrr
2017-03-31 15:53:51 +02:00
committed by atlimit8
parent 6f19379a2b
commit aa8d9f5dda
5 changed files with 114 additions and 20 deletions

View File

@@ -11,6 +11,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using OpenRA.Activities; using OpenRA.Activities;
using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Orders;
@@ -42,9 +43,6 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Cursor to display when unable to (un)deploy the actor.")] [Desc("Cursor to display when unable to (un)deploy the actor.")]
public readonly string DeployBlockedCursor = "deploy-blocked"; public readonly string DeployBlockedCursor = "deploy-blocked";
[SequenceReference, Desc("Animation to play for deploying/undeploying.")]
public readonly string DeployAnimation = null;
[Desc("Facing that the actor must face before deploying. Set to -1 to deploy regardless of facing.")] [Desc("Facing that the actor must face before deploying. Set to -1 to deploy regardless of facing.")]
public readonly int Facing = -1; public readonly int Facing = -1;
@@ -62,16 +60,16 @@ namespace OpenRA.Mods.Common.Traits
public enum DeployState { Undeployed, Deploying, Deployed, Undeploying } public enum DeployState { Undeployed, Deploying, Deployed, Undeploying }
public class GrantConditionOnDeploy : IResolveOrder, IIssueOrder, INotifyCreated public class GrantConditionOnDeploy : IResolveOrder, IIssueOrder, INotifyCreated, INotifyDeployComplete
{ {
readonly Actor self; readonly Actor self;
readonly GrantConditionOnDeployInfo info; readonly GrantConditionOnDeployInfo info;
readonly bool checkTerrainType; readonly bool checkTerrainType;
readonly bool canTurn; readonly bool canTurn;
readonly Lazy<WithSpriteBody> body;
DeployState deployState; DeployState deployState;
ConditionManager conditionManager; ConditionManager conditionManager;
INotifyDeployTriggered[] notify;
int deployedToken = ConditionManager.InvalidConditionToken; int deployedToken = ConditionManager.InvalidConditionToken;
int undeployedToken = ConditionManager.InvalidConditionToken; int undeployedToken = ConditionManager.InvalidConditionToken;
@@ -81,7 +79,6 @@ namespace OpenRA.Mods.Common.Traits
this.info = info; this.info = info;
checkTerrainType = info.AllowedTerrainTypes.Count > 0; checkTerrainType = info.AllowedTerrainTypes.Count > 0;
canTurn = self.Info.HasTraitInfo<IFacingInfo>(); canTurn = self.Info.HasTraitInfo<IFacingInfo>();
body = Exts.Lazy(self.TraitOrDefault<WithSpriteBody>);
if (init.Contains<DeployStateInit>()) if (init.Contains<DeployStateInit>())
deployState = init.Get<DeployStateInit, DeployState>(); deployState = init.Get<DeployStateInit, DeployState>();
} }
@@ -89,6 +86,7 @@ namespace OpenRA.Mods.Common.Traits
public void Created(Actor self) public void Created(Actor self)
{ {
conditionManager = self.TraitOrDefault<ConditionManager>(); conditionManager = self.TraitOrDefault<ConditionManager>();
notify = self.TraitsImplementing<INotifyDeployTriggered>().ToArray();
switch (deployState) switch (deployState)
{ {
@@ -192,6 +190,16 @@ namespace OpenRA.Mods.Common.Traits
return ramp == 0; return ramp == 0;
} }
void INotifyDeployComplete.FinishedDeploy(Actor self)
{
OnDeployCompleted();
}
void INotifyDeployComplete.FinishedUndeploy(Actor self)
{
OnUndeployCompleted();
}
/// <summary>Play deploy sound and animation.</summary> /// <summary>Play deploy sound and animation.</summary>
void Deploy() { Deploy(false); } void Deploy() { Deploy(false); }
void Deploy(bool init) void Deploy(bool init)
@@ -212,10 +220,11 @@ namespace OpenRA.Mods.Common.Traits
// If there is no animation to play just grant the condition that is used while deployed. // If there is no animation to play just grant the condition that is used while deployed.
// Alternatively, play the deploy animation and then grant the condition. // Alternatively, play the deploy animation and then grant the condition.
if (string.IsNullOrEmpty(info.DeployAnimation) || body.Value == null) if (!notify.Any())
OnDeployCompleted(); OnDeployCompleted();
else else
body.Value.PlayCustomAnimation(self, info.DeployAnimation, OnDeployCompleted); foreach (var n in notify)
n.Deploy(self);
} }
/// <summary>Play undeploy sound and animation and after that revoke the condition.</summary> /// <summary>Play undeploy sound and animation and after that revoke the condition.</summary>
@@ -234,10 +243,11 @@ namespace OpenRA.Mods.Common.Traits
// If there is no animation to play just grant the condition that is used while undeployed. // If there is no animation to play just grant the condition that is used while undeployed.
// Alternatively, play the undeploy animation and then grant the condition. // Alternatively, play the undeploy animation and then grant the condition.
if (string.IsNullOrEmpty(info.DeployAnimation) || body.Value == null) if (!notify.Any())
OnUndeployCompleted(); OnUndeployCompleted();
else else
body.Value.PlayCustomAnimationBackwards(self, info.DeployAnimation, OnUndeployCompleted); foreach (var n in notify)
n.Undeploy(self);
} }
void OnDeployStarted() void OnDeployStarted()

View File

@@ -10,28 +10,32 @@
#endregion #endregion
using System; using System;
using System.Linq;
using OpenRA.Activities; using OpenRA.Activities;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render namespace OpenRA.Mods.Common.Traits.Render
{ {
[Desc("Replaces the sprite during construction.")] [Desc("Replaces the sprite during construction/deploy/undeploy.")]
public class WithMakeAnimationInfo : ITraitInfo, Requires<WithSpriteBodyInfo> public class WithMakeAnimationInfo : ITraitInfo, Requires<WithSpriteBodyInfo>
{ {
[Desc("Sequence name to use")] [Desc("Sequence name to use.")]
[SequenceReference] public readonly string Sequence = "make"; [SequenceReference] public readonly string Sequence = "make";
[GrantedConditionReference] [GrantedConditionReference]
[Desc("The condition to grant to self while the make animation is playing.")] [Desc("The condition to grant to self while the make animation is playing.")]
public readonly string Condition = null; public readonly string Condition = null;
[Desc("Apply to sprite bodies with these names.")]
public readonly string[] BodyNames = { "body" };
public object Create(ActorInitializer init) { return new WithMakeAnimation(init, this); } public object Create(ActorInitializer init) { return new WithMakeAnimation(init, this); }
} }
public class WithMakeAnimation : INotifyCreated public class WithMakeAnimation : INotifyCreated, INotifyDeployTriggered
{ {
readonly WithMakeAnimationInfo info; readonly WithMakeAnimationInfo info;
readonly WithSpriteBody wsb; readonly WithSpriteBody[] wsbs;
ConditionManager conditionManager; ConditionManager conditionManager;
int token = ConditionManager.InvalidConditionToken; int token = ConditionManager.InvalidConditionToken;
@@ -40,7 +44,7 @@ namespace OpenRA.Mods.Common.Traits.Render
{ {
this.info = info; this.info = info;
var self = init.Self; var self = init.Self;
wsb = self.Trait<WithSpriteBody>(); wsbs = self.TraitsImplementing<WithSpriteBody>().Where(w => info.BodyNames.Contains(w.Info.Name)).ToArray();
} }
void INotifyCreated.Created(Actor self) void INotifyCreated.Created(Actor self)
@@ -56,6 +60,11 @@ namespace OpenRA.Mods.Common.Traits.Render
if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && token == ConditionManager.InvalidConditionToken) if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && token == ConditionManager.InvalidConditionToken)
token = conditionManager.GrantCondition(self, info.Condition); token = conditionManager.GrantCondition(self, info.Condition);
var wsb = wsbs.FirstOrDefault(Exts.IsTraitEnabled);
if (wsb == null)
return;
wsb.PlayCustomAnimation(self, info.Sequence, () => wsb.PlayCustomAnimation(self, info.Sequence, () =>
{ {
if (token != ConditionManager.InvalidConditionToken) if (token != ConditionManager.InvalidConditionToken)
@@ -71,6 +80,11 @@ namespace OpenRA.Mods.Common.Traits.Render
if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && token == ConditionManager.InvalidConditionToken) if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && token == ConditionManager.InvalidConditionToken)
token = conditionManager.GrantCondition(self, info.Condition); token = conditionManager.GrantCondition(self, info.Condition);
var wsb = wsbs.FirstOrDefault(Exts.IsTraitEnabled);
if (wsb == null)
return;
wsb.PlayCustomAnimationBackwards(self, info.Sequence, () => wsb.PlayCustomAnimationBackwards(self, info.Sequence, () =>
{ {
if (token != ConditionManager.InvalidConditionToken) if (token != ConditionManager.InvalidConditionToken)
@@ -85,10 +99,13 @@ namespace OpenRA.Mods.Common.Traits.Render
{ {
Reverse(self, () => Reverse(self, () =>
{ {
var wsb = wsbs.FirstOrDefault(Exts.IsTraitEnabled);
// HACK: The actor remains alive and active for one tick before the followup activity // HACK: The actor remains alive and active for one tick before the followup activity
// (sell/transform/etc) runs. This causes visual glitches that we attempt to minimize // (sell/transform/etc) runs. This causes visual glitches that we attempt to minimize
// by forcing the animation to frame 0 and regranting the make condition. // by forcing the animation to frame 0 and regranting the make condition.
// These workarounds will break the actor if the followup activity doesn't dispose it! // These workarounds will break the actor if the followup activity doesn't dispose it!
if (wsb != null)
wsb.DefaultAnimation.PlayFetchIndex(info.Sequence, () => 0); wsb.DefaultAnimation.PlayFetchIndex(info.Sequence, () => 0);
if (conditionManager != null && !string.IsNullOrEmpty(info.Condition)) if (conditionManager != null && !string.IsNullOrEmpty(info.Condition))
@@ -97,5 +114,55 @@ namespace OpenRA.Mods.Common.Traits.Render
self.QueueActivity(queued, activity); self.QueueActivity(queued, activity);
}); });
} }
// TODO: Make this use Forward instead
void INotifyDeployTriggered.Deploy(Actor self)
{
var notified = false;
foreach (var wsb in wsbs)
{
if (wsb.IsTraitDisabled)
continue;
var notify = self.TraitsImplementing<INotifyDeployComplete>();
wsb.PlayCustomAnimation(self, info.Sequence, () =>
{
if (notified)
return;
foreach (var n in notify)
{
n.FinishedDeploy(self);
notified = true;
}
});
}
}
// TODO: Make this use Reverse instead
void INotifyDeployTriggered.Undeploy(Actor self)
{
var notified = false;
foreach (var wsb in wsbs)
{
if (wsb.IsTraitDisabled)
continue;
var notify = self.TraitsImplementing<INotifyDeployComplete>();
wsb.PlayCustomAnimationBackwards(self, info.Sequence, () =>
{
if (notified)
return;
foreach (var n in notify)
{
n.FinishedUndeploy(self);
notified = true;
}
});
}
}
} }
} }

View File

@@ -165,7 +165,24 @@ namespace OpenRA.Mods.Common.Traits
bool IsOverlayActive(ActorInfo ai); bool IsOverlayActive(ActorInfo ai);
} }
public interface INotifyTransform { void BeforeTransform(Actor self); void OnTransform(Actor self); void AfterTransform(Actor toActor); } public interface INotifyTransform
{
void BeforeTransform(Actor self);
void OnTransform(Actor self);
void AfterTransform(Actor toActor);
}
public interface INotifyDeployComplete
{
void FinishedDeploy(Actor self);
void FinishedUndeploy(Actor self);
}
public interface INotifyDeployTriggered
{
void Deploy(Actor self);
void Undeploy(Actor self);
}
public interface IAcceptResourcesInfo : ITraitInfo { } public interface IAcceptResourcesInfo : ITraitInfo { }
public interface IAcceptResources public interface IAcceptResources

View File

@@ -117,10 +117,10 @@ TTNK:
MaxHeightDelta: 3 MaxHeightDelta: 3
RenderSprites: RenderSprites:
Image: ttnk Image: ttnk
WithMakeAnimation:
GrantConditionOnDeploy: GrantConditionOnDeploy:
DeployedCondition: deployed DeployedCondition: deployed
UndeployedCondition: undeployed UndeployedCondition: undeployed
DeployAnimation: make
Facing: 160 Facing: 160
AllowedTerrainTypes: Clear, Road, DirtRoad, Rough AllowedTerrainTypes: Clear, Road, DirtRoad, Rough
DeploySound: place2.aud DeploySound: place2.aud
@@ -211,10 +211,10 @@ ART2:
LightAmbientColor: 0.4, 0.4, 0.4 LightAmbientColor: 0.4, 0.4, 0.4
RenderSprites: RenderSprites:
Image: art2 Image: art2
WithMakeAnimation:
GrantConditionOnDeploy: GrantConditionOnDeploy:
DeployedCondition: deployed DeployedCondition: deployed
UndeployedCondition: undeployed UndeployedCondition: undeployed
DeployAnimation: make
Facing: 96 Facing: 96
AllowedTerrainTypes: Clear, Road, DirtRoad, Rough AllowedTerrainTypes: Clear, Road, DirtRoad, Rough
DeploySound: place2.aud DeploySound: place2.aud

View File

@@ -140,6 +140,7 @@ LPST:
RequiresCondition: !undeployed RequiresCondition: !undeployed
Range: 8c0 Range: 8c0
MaxHeightDelta: 3 MaxHeightDelta: 3
WithMakeAnimation:
GrantCondition@PREVIEWWORKAROUND: GrantCondition@PREVIEWWORKAROUND:
Condition: real-actor Condition: real-actor
RenderSprites: RenderSprites:
@@ -150,7 +151,6 @@ LPST:
GrantConditionOnDeploy: GrantConditionOnDeploy:
DeployedCondition: deployed DeployedCondition: deployed
UndeployedCondition: undeployed UndeployedCondition: undeployed
DeployAnimation: make
Facing: 160 Facing: 160
AllowedTerrainTypes: Clear, Road, DirtRoad, Rough AllowedTerrainTypes: Clear, Road, DirtRoad, Rough
DeploySound: place2.aud DeploySound: place2.aud