diff --git a/OpenRA.Game/Map/ActorReference.cs b/OpenRA.Game/Map/ActorReference.cs index c5b59b89f2..192d1c5f16 100755 --- a/OpenRA.Game/Map/ActorReference.cs +++ b/OpenRA.Game/Map/ActorReference.cs @@ -15,6 +15,8 @@ using OpenRA.Primitives; namespace OpenRA { + public interface ISuppressInitExport { } + public class ActorReference : IEnumerable { public string Type; @@ -51,6 +53,9 @@ namespace OpenRA var ret = new MiniYaml(Type); foreach (var init in InitDict) { + if (init is ISuppressInitExport) + continue; + var initName = init.GetType().Name; ret.Nodes.Add(new MiniYamlNode(initName.Substring(0, initName.Length - 4), FieldSaver.Save(init))); } diff --git a/OpenRA.Mods.Common/Graphics/ActorPreview.cs b/OpenRA.Mods.Common/Graphics/ActorPreview.cs index 098f336b3a..d5a0f439c1 100644 --- a/OpenRA.Mods.Common/Graphics/ActorPreview.cs +++ b/OpenRA.Mods.Common/Graphics/ActorPreview.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using OpenRA.Graphics; using OpenRA.Primitives; +using OpenRA.Traits; namespace OpenRA.Mods.Common.Graphics { @@ -41,5 +42,32 @@ namespace OpenRA.Mods.Common.Graphics public T Get() where T : IActorInit { return dict.Get(); } public U Get() where T : IActorInit { return dict.Get().Value(World); } public bool Contains() where T : IActorInit { return dict.Contains(); } + + public DamageState GetDamageState() + { + var health = dict.GetOrDefault(); + + if (health == null) + return DamageState.Undamaged; + + var hf = health.Value(null); + + if (hf <= 0) + return DamageState.Dead; + + if (hf < 0.25f) + return DamageState.Critical; + + if (hf < 0.5f) + return DamageState.Heavy; + + if (hf < 0.75f) + return DamageState.Medium; + + if (hf < 1.0f) + return DamageState.Light; + + return DamageState.Undamaged; + } } } diff --git a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs index 1ae633bb4c..8916170d83 100644 --- a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs @@ -169,7 +169,8 @@ namespace OpenRA.Mods.Common.Orders { var td = new TypeDictionary() { - new RaceInit(race) + new RaceInit(race), + new HideBibPreviewInit() }; var init = new ActorPreviewInitializer(rules.Actors[building], producer.Owner, wr, td); diff --git a/OpenRA.Mods.Common/Traits/Buildings/Bib.cs b/OpenRA.Mods.Common/Traits/Buildings/Bib.cs index f4feaf7050..8f71047021 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/Bib.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/Bib.cs @@ -8,18 +8,60 @@ */ #endregion +using System.Collections.Generic; using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class BibInfo : ITraitInfo, Requires, Requires + public class BibInfo : ITraitInfo, Requires, IRenderActorPreviewSpritesInfo, Requires { public readonly string Sequence = "bib"; public readonly string Palette = "terrain"; public readonly bool HasMinibib = false; public object Create(ActorInitializer init) { return new Bib(init.Self, this); } + + public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) + { + if (init.Contains() && init.Get()) + yield break; + + if (Palette != null) + p = init.WorldRenderer.Palette(Palette); + + var bi = init.Actor.Traits.Get(); + + var width = bi.Dimensions.X; + var bibOffset = bi.Dimensions.Y - 1; + var centerOffset = FootprintUtils.CenterOffset(init.World, bi); + var rows = HasMinibib ? 1 : 2; + var map = init.World.Map; + var location = CPos.Zero; + + if (init.Contains()) + location = init.Get(); + + for (var i = 0; i < rows * width; i++) + { + var index = i; + var anim = new Animation(init.World, image); + var cellOffset = new CVec(i % width, i / width + bibOffset); + var cell = location + cellOffset; + + // Some mods may define terrain-specific bibs + var terrain = map.GetTerrainInfo(cell).Type; + var testSequence = Sequence + "-" + terrain; + var sequence = anim.HasSequence(testSequence) ? testSequence : Sequence; + anim.PlayFetchIndex(sequence, () => index); + anim.IsDecoration = true; + + // 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); + } + } } public class Bib : INotifyAddedToWorld, INotifyRemovedFromWorld @@ -74,4 +116,12 @@ namespace OpenRA.Mods.Common.Traits rs.Remove("bib_{0}".F(i)); } } + + public class HideBibPreviewInit : IActorInit, ISuppressInitExport + { + [FieldFromYamlKey] readonly bool value = true; + public HideBibPreviewInit() { } + public HideBibPreviewInit(bool init) { value = init; } + public bool Value(World world) { return value; } + } } diff --git a/OpenRA.Mods.Common/Traits/Cargo.cs b/OpenRA.Mods.Common/Traits/Cargo.cs index c973075599..389d21162f 100644 --- a/OpenRA.Mods.Common/Traits/Cargo.cs +++ b/OpenRA.Mods.Common/Traits/Cargo.cs @@ -349,7 +349,7 @@ namespace OpenRA.Mods.Common.Traits public interface INotifyPassengerEntered { void PassengerEntered(Actor self, Actor passenger); } public interface INotifyPassengerExited { void PassengerExited(Actor self, Actor passenger); } - public class RuntimeCargoInit : IActorInit + public class RuntimeCargoInit : IActorInit, ISuppressInitExport { [FieldFromYamlKey] readonly Actor[] value = { }; diff --git a/OpenRA.Mods.Common/Traits/Render/RenderBuildingSilo.cs b/OpenRA.Mods.Common/Traits/Render/RenderBuildingSilo.cs index 5f952dc3d6..4016606988 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderBuildingSilo.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderBuildingSilo.cs @@ -23,7 +23,7 @@ namespace OpenRA.Mods.Common.Traits { // Show a static frame instead of animating all of the fullness states var anim = new Animation(init.World, image, () => 0); - anim.PlayFetchIndex(Sequence, () => 0); + anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence), () => 0); yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale); } diff --git a/OpenRA.Mods.Common/Traits/Render/RenderBuildingTurreted.cs b/OpenRA.Mods.Common/Traits/Render/RenderBuildingTurreted.cs index 9916134d61..337847128a 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderBuildingTurreted.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderBuildingTurreted.cs @@ -28,7 +28,7 @@ namespace OpenRA.Mods.Common.Traits // Show the correct turret facing var anim = new Animation(init.World, image, () => t.InitialFacing); - anim.PlayRepeating(Sequence); + anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence)); yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale); } diff --git a/OpenRA.Mods.Common/Traits/Render/RenderBuildingWall.cs b/OpenRA.Mods.Common/Traits/Render/RenderBuildingWall.cs index 26f5a1c279..37315a130b 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderBuildingWall.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderBuildingWall.cs @@ -24,9 +24,44 @@ namespace OpenRA.Mods.Common.Traits public override IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { - // Show a static frame instead of animating all of the wall states + var adjacent = 0; + + if (init.Contains()) + { + var location = CPos.Zero; + if (init.Contains()) + location = init.Get(); + + var neighbours = init.Get>(); + foreach (var kv in neighbours) + { + var haveNeighbour = false; + foreach (var n in kv.Value) + { + var rb = init.World.Map.Rules.Actors[n].Traits.GetOrDefault(); + if (rb != null && rb.Type == Type) + { + haveNeighbour = true; + break; + } + } + + if (!haveNeighbour) + continue; + + if (kv.Key == location + new CVec(0, -1)) + adjacent |= 1; + else if (kv.Key == location + new CVec(+1, 0)) + adjacent |= 2; + else if (kv.Key == location + new CVec(0, +1)) + adjacent |= 4; + else if (kv.Key == location + new CVec(-1, 0)) + adjacent |= 8; + } + } + var anim = new Animation(init.World, image, () => 0); - anim.PlayFetchIndex(Sequence, () => 0); + anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence), () => adjacent); yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale); } @@ -110,4 +145,12 @@ namespace OpenRA.Mods.Common.Traits UpdateNeighbours(self); } } + + public class RuntimeNeighbourInit : IActorInit>, ISuppressInitExport + { + [FieldFromYamlKey] readonly Dictionary value = null; + public RuntimeNeighbourInit() { } + public RuntimeNeighbourInit(Dictionary init) { value = init; } + public Dictionary Value(World world) { return value; } + } } diff --git a/OpenRA.Mods.Common/Traits/Render/RenderSimple.cs b/OpenRA.Mods.Common/Traits/Render/RenderSimple.cs index 80fd682124..95a877373a 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderSimple.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderSimple.cs @@ -28,7 +28,8 @@ namespace OpenRA.Mods.Common.Traits var facing = ifacing != null ? init.Contains() ? init.Get() : ifacing.GetInitialFacing() : 0; var anim = new Animation(init.World, image, () => facing); - anim.PlayRepeating(Sequence); + anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence)); + yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale); } diff --git a/OpenRA.Mods.Common/Traits/Render/WithBarrel.cs b/OpenRA.Mods.Common/Traits/Render/WithBarrel.cs index cd894168b3..666b009f1a 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithBarrel.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithBarrel.cs @@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Traits .First(tt => tt.Turret == armament.Turret); var anim = new Animation(init.World, image, () => t.InitialFacing); - anim.Play(Sequence); + 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)); diff --git a/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs b/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs index 11ceea5972..458a668437 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithCrateBody.cs @@ -9,14 +9,16 @@ #endregion using System; +using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Renders crates with both water and land variants.")] - class WithCrateBodyInfo : ITraitInfo, Requires + class WithCrateBodyInfo : ITraitInfo, Requires, IQuantizeBodyOrientationInfo, IRenderActorPreviewSpritesInfo { public readonly string[] Images = { "crate" }; @@ -24,6 +26,15 @@ namespace OpenRA.Mods.Common.Traits public readonly string[] XmasImages = { }; public object Create(ActorInitializer init) { return new WithCrateBody(init.Self, this); } + + public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) + { + var anim = new Animation(init.World, Images.First(), () => 0); + anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), "idle")); + yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale); + } + + public int QuantizedBodyFacings(ActorInfo ai, SequenceProvider sequenceProvider, string race) { return 1; } } class WithCrateBody : INotifyParachuteLanded diff --git a/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs index 75b381cdd8..004f139c20 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs @@ -40,10 +40,13 @@ namespace OpenRA.Mods.Common.Traits if (UpgradeMinEnabledLevel > 0) yield break; + if (Palette != null) + p = init.WorldRenderer.Palette(Palette); + var body = init.Actor.Traits.Get(); var facing = init.Contains() ? init.Get() : 0; var anim = new Animation(init.World, image, () => facing); - anim.PlayRepeating(Sequence); + 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)); diff --git a/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs b/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs index 471d042486..7cc8c4713a 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs @@ -35,7 +35,7 @@ namespace OpenRA.Mods.Common.Traits facing = init.Contains() ? init.Get() : ifacing.GetInitialFacing(); var anim = new Animation(init.World, image, () => facing); - anim.PlayRepeating(StandSequences.First()); + anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), StandSequences.First())); yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale); } diff --git a/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs index 40c56daba9..c8de8beca9 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs @@ -27,7 +27,7 @@ namespace OpenRA.Mods.TS.Traits public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { var anim = new Animation(init.World, image, () => 0); - anim.PlayFetchIndex(Sequence, () => 0); + anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence), () => 0); var bi = init.Actor.Traits.Get(); var offset = FootprintUtils.CenterOffset(init.World, bi).Y + 512; // Additional 512 units move from center -> top of cell diff --git a/OpenRA.Mods.Common/Traits/Render/WithRotor.cs b/OpenRA.Mods.Common/Traits/Render/WithRotor.cs index 60c73a5659..579607f866 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithRotor.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithRotor.cs @@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Traits var body = init.Actor.Traits.Get(); var facing = init.Contains() ? init.Get() : 0; var anim = new Animation(init.World, image, () => facing); - anim.PlayRepeating(Sequence); + 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)); diff --git a/OpenRA.Mods.Common/Traits/Render/WithTurret.cs b/OpenRA.Mods.Common/Traits/Render/WithTurret.cs index a5c254ee2c..c94fc0fd8e 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithTurret.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithTurret.cs @@ -48,11 +48,11 @@ namespace OpenRA.Mods.Common.Traits var turretFacing = init.Contains() ? init.Get() : t.InitialFacing; var anim = new Animation(init.World, image, () => turretFacing); - anim.Play(Sequence); + 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); + yield return new SpriteActorPreview(anim, offset, -(offset.Y + offset.Z) + 1, p, rs.Scale); } } diff --git a/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs b/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs index 93cc375a42..cd653f15e4 100644 --- a/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs +++ b/OpenRA.Mods.Common/Traits/World/SpawnMapActors.cs @@ -41,5 +41,5 @@ namespace OpenRA.Mods.Common.Traits } } - public class SkipMakeAnimsInit : IActorInit { } + public class SkipMakeAnimsInit : IActorInit, ISuppressInitExport { } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs index a44ee3e553..dc221c6339 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs @@ -10,6 +10,7 @@ using System; using OpenRA.Graphics; +using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; using OpenRA.Widgets; @@ -26,7 +27,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic var preview = widget.GetOrNull("PREVIEW"); var actor = world.Map.Rules.Actors[actorType]; - preview.SetPreview(actor, world.WorldActor.Owner, new TypeDictionary()); + + var td = new TypeDictionary(); + td.Add(new HideBibPreviewInit()); + + preview.SetPreview(actor, world.WorldActor.Owner, td); var hueSlider = widget.Get("HUE"); var mixer = widget.Get("MIXER"); diff --git a/mods/cnc/rules/misc.yaml b/mods/cnc/rules/misc.yaml index 384137e931..f6f7af2ae7 100644 --- a/mods/cnc/rules/misc.yaml +++ b/mods/cnc/rules/misc.yaml @@ -34,12 +34,14 @@ mpspawn: Immobile: OccupiesSpace: false RenderEditorOnly: + Palette: chrome BodyOrientation: waypoint: Immobile: OccupiesSpace: false RenderEditorOnly: + Palette: chrome BodyOrientation: ^fact.colorpicker: