diff --git a/OpenRA.Game/Graphics/Animation.cs b/OpenRA.Game/Graphics/Animation.cs index fcd3325bea..f2f51e4918 100644 --- a/OpenRA.Game/Graphics/Animation.cs +++ b/OpenRA.Game/Graphics/Animation.cs @@ -47,7 +47,7 @@ namespace OpenRA.Graphics this.facingFunc = facingFunc; } - int CurrentFrame { get { return backwards ? CurrentSequence.Start + CurrentSequence.Length - frame - 1 : frame; } } + public int CurrentFrame { get { return backwards ? CurrentSequence.Start + CurrentSequence.Length - frame - 1 : frame; } } public Sprite Image { get { return CurrentSequence.GetSprite(CurrentFrame, facingFunc()); } } public IEnumerable Render(WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale) @@ -139,6 +139,24 @@ namespace OpenRA.Graphics tickFunc = () => frame = func(); } + public void PlayFetchDirection(string sequenceName, Func direction) + { + tickAlways = false; + CurrentSequence = sequenceProvider.GetSequence(name, sequenceName); + timeUntilNextFrame = CurrentSequence != null ? CurrentSequence.Tick : defaultTick; + + frame = 0; + tickFunc = () => + { + var d = direction(); + if (d > 0 && ++frame >= CurrentSequence.Length) + frame = 0; + + if (d < 0 && --frame < 0) + frame = CurrentSequence.Length - 1; + }; + } + int timeUntilNextFrame; Action tickFunc; diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index c617cbea48..42336b5898 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -370,7 +370,6 @@ - @@ -405,6 +404,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/Render/RenderBuildingWarFactory.cs b/OpenRA.Mods.Common/Traits/Render/RenderBuildingWarFactory.cs deleted file mode 100644 index 498764b8da..0000000000 --- a/OpenRA.Mods.Common/Traits/Render/RenderBuildingWarFactory.cs +++ /dev/null @@ -1,96 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.Common.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - class RenderBuildingWarFactoryInfo : RenderBuildingInfo - { - public override object Create(ActorInitializer init) { return new RenderBuildingWarFactory(init, this); } - - public override IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) - { - foreach (var orig in base.RenderPreviewSprites(init, rs, image, facings, p)) - yield return orig; - - // Show additional roof overlay - var anim = new Animation(init.World, image, () => 0); - anim.PlayRepeating("idle-top"); - - var bi = init.Actor.Traits.Get(); - var offset = FootprintUtils.CenterOffset(init.World, bi).Y + 512; - yield return new SpriteActorPreview(anim, WVec.Zero, offset, p, rs.Scale); - } - } - - class RenderBuildingWarFactory : RenderBuilding, INotifyBuildComplete, ITick, INotifyProduction, INotifySold, ISync - { - Animation roof; - [Sync] bool isOpen; - [Sync] CPos openExit; - bool buildComplete; - - public RenderBuildingWarFactory(ActorInitializer init, RenderBuildingInfo info) - : base(init, info) - { - roof = new Animation(init.World, GetImage(init.Self)); - var bi = init.Self.Info.Traits.Get(); - - // Additional 512 units move from center -> top of cell - var offset = FootprintUtils.CenterOffset(init.World, bi).Y + 512; - Add("roof", new AnimationWithOffset(roof, null, - () => !buildComplete, offset)); - } - - public override void BuildingComplete(Actor self) - { - roof.Play(NormalizeSequence(self, - self.GetDamageState() > DamageState.Heavy ? "damaged-idle-top" : "idle-top")); - buildComplete = true; - } - - public override void Tick(Actor self) - { - base.Tick(self); - if (isOpen && !self.World.ActorMap.GetUnitsAt(openExit).Any(a => a != self)) - { - isOpen = false; - roof.PlayBackwardsThen(NormalizeSequence(self, "build-top"), - () => roof.Play(NormalizeSequence(self, "idle-top"))); - } - } - - public override void DamageStateChanged(Actor self, AttackInfo e) - { - if (roof.CurrentSequence != null) - { - if (e.DamageState >= DamageState.Heavy) - roof.ReplaceAnim("damaged-" + roof.CurrentSequence.Name); - else - roof.ReplaceAnim(roof.CurrentSequence.Name.Replace("damaged-", "")); - } - - base.DamageStateChanged(self, e); - } - - public void UnitProduced(Actor self, Actor other, CPos exit) - { - roof.PlayThen(NormalizeSequence(self, "build-top"), () => { isOpen = true; openExit = exit; }); - } - - public void Selling(Actor self) { Remove("roof"); } - public void Sold(Actor self) { } - } -} diff --git a/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs new file mode 100644 index 0000000000..40c56daba9 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs @@ -0,0 +1,86 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Mods.Common.Traits; +using OpenRA.Traits; + +namespace OpenRA.Mods.TS.Traits +{ + [Desc("Play an animation when a unit exits or blocks the exit after production finished.")] + class WithProductionDoorOverlayInfo : ITraitInfo, IRenderActorPreviewSpritesInfo, Requires, Requires, Requires + { + public readonly string Sequence = "build-door"; + + public object Create(ActorInitializer init) { return new WithProductionDoorOverlay(init.Self, this); } + + 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); + + var bi = init.Actor.Traits.Get(); + 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); + } + } + + class WithProductionDoorOverlay : INotifyBuildComplete, ITick, INotifyProduction, INotifySold, INotifyDamageStateChanged + { + readonly Animation door; + + int desiredFrame; + + CPos openExit; + bool buildComplete; + + public WithProductionDoorOverlay(Actor self, WithProductionDoorOverlayInfo info) + { + var renderSprites = self.Trait(); + door = new Animation(self.World, renderSprites.GetImage(self)); + door.PlayFetchDirection(RenderSprites.NormalizeSequence(door, self.GetDamageState(), info.Sequence), + () => desiredFrame - door.CurrentFrame); + + var buildingInfo = self.Info.Traits.Get(); + + var offset = FootprintUtils.CenterOffset(self.World, buildingInfo).Y + 512; + renderSprites.Add("door_overlay_{0}".F(info.Sequence), new AnimationWithOffset(door, null, () => !buildComplete, offset)); + } + + public void BuildingComplete(Actor self) + { + buildComplete = true; + } + + public void Tick(Actor self) + { + if (desiredFrame > 0 && !self.World.ActorMap.GetUnitsAt(openExit).Any(a => a != self)) + desiredFrame = 0; + } + + public void DamageStateChanged(Actor self, AttackInfo e) + { + if (door.CurrentSequence != null) + door.ReplaceAnim(RenderSprites.NormalizeSequence(door, e.DamageState, door.CurrentSequence.Name)); + } + + public void UnitProduced(Actor self, Actor other, CPos exit) + { + openExit = exit; + desiredFrame = door.CurrentSequence.Length - 1; + } + + public void Selling(Actor self) { buildComplete = false; } + public void Sold(Actor self) { } + } +} diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 0f55a7e5f1..1f5f80ce24 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -836,6 +836,25 @@ namespace OpenRA.Mods.Common.UtilityCommands node.Key = "BlocksProjectiles"; } + if (engineVersion < 20150425) + { + if (depth == 0) + { + var warFact = node.Value.Nodes.FirstOrDefault(n => n.Key.StartsWith("RenderBuildingWarFactory")); + if (warFact != null) + { + warFact.Key = "RenderBuilding"; + + if (node.Value.Nodes.Any(w => w.Key == "-RenderBuilding")) + node.Value.Nodes.RemoveAll(p => p.Key == "-RenderBuilding"); + + var doorOverlay = new MiniYamlNode("WithProductionDoorOverlay", ""); + doorOverlay.Value.Nodes.Add(new MiniYamlNode("Sequence", "build-top")); + node.Value.Nodes.Add(doorOverlay); + } + } + } + UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); } } diff --git a/mods/cnc/rules/structures.yaml b/mods/cnc/rules/structures.yaml index 70b06a605f..4cae60fd46 100644 --- a/mods/cnc/rules/structures.yaml +++ b/mods/cnc/rules/structures.yaml @@ -363,8 +363,8 @@ WEAP: RevealsShroud: Range: 4c0 Bib: - -RenderBuilding: - RenderBuildingWarFactory: + WithProductionDoorOverlay: + Sequence: build-top RallyPoint: RallyPoint: 0,3 Exit@1: diff --git a/mods/cnc/sequences/structures.yaml b/mods/cnc/sequences/structures.yaml index 730103a8e1..2a33aff6c9 100644 --- a/mods/cnc/sequences/structures.yaml +++ b/mods/cnc/sequences/structures.yaml @@ -147,9 +147,6 @@ weap: damaged-build-top: weap2 Start: 10 Length: 10 - idle-top: weap2 - damaged-idle-top: weap2 - Start: 4 make: weapmake Length: * Tick: 80 diff --git a/mods/d2k/rules/starport.yaml b/mods/d2k/rules/starport.yaml index 90b7abae29..51db9ef7f2 100644 --- a/mods/d2k/rules/starport.yaml +++ b/mods/d2k/rules/starport.yaml @@ -83,7 +83,7 @@ combato.starport: Cost: 875 RenderUnit: Image: combato - + carryall.starport: Inherits: carryall Valued: diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index 0038aec005..cfe97627c2 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -200,8 +200,7 @@ refinery: DeliveryOffset: 2,2 DeliveringActor: carryall.reinforce Facing: 160 - -RenderBuilding: - RenderBuildingWarFactory: + RenderBuilding: Image: refinery.harkonnen RaceImages: atreides: refinery.atreides diff --git a/mods/ra/rules/fakes.yaml b/mods/ra/rules/fakes.yaml index 9d39c1e6f3..c24069c28c 100644 --- a/mods/ra/rules/fakes.yaml +++ b/mods/ra/rules/fakes.yaml @@ -37,9 +37,10 @@ WEAF: Footprint: xxx xxx Dimensions: 3,2 Bib: - -RenderBuilding: - RenderBuildingWarFactory: + RenderBuilding: Image: WEAP + WithIdleOverlay@ROOF: + Sequence: idle-top Valued: Cost: 200 diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index 0c634e1dff..8514dc97f2 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -761,8 +761,8 @@ WEAP: RevealsShroud: Range: 4c0 Bib: - -RenderBuilding: - RenderBuildingWarFactory: + WithProductionDoorOverlay: + Sequence: build-top RallyPoint: Exit@1: SpawnOffset: 213,-128,0 diff --git a/mods/ra/sequences/structures.yaml b/mods/ra/sequences/structures.yaml index cfef2780a6..5c95b58876 100644 --- a/mods/ra/sequences/structures.yaml +++ b/mods/ra/sequences/structures.yaml @@ -236,9 +236,6 @@ weap: damaged-build-top: weap2 Start: 4 Length: 4 - idle-top: weap2 - damaged-idle-top: weap2 - Start: 4 bib: bib2 Length: * UseTilesetExtension: true diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml index d9fd9790a9..e6835d98ae 100644 --- a/mods/ts/rules/defaults.yaml +++ b/mods/ts/rules/defaults.yaml @@ -486,7 +486,7 @@ UpgradeManager: MustBeDestroyed: -^Plane: +^Plane: Inherits: ^Helicopter -Helicopter: Plane: diff --git a/mods/ts/rules/gdi-structures.yaml b/mods/ts/rules/gdi-structures.yaml index 6ecf481663..a3138fcf3e 100644 --- a/mods/ts/rules/gdi-structures.yaml +++ b/mods/ts/rules/gdi-structures.yaml @@ -123,8 +123,6 @@ GAWEAP: HP: 1000 RevealsShroud: Range: 4c0 - -RenderBuilding: - RenderBuildingWarFactory: RallyPoint: RallyPoint: 6,1 Exit@1: @@ -134,6 +132,9 @@ GAWEAP: Produces: Vehicle PrimaryBuilding: ProductionBar: + WithIdleOverlay@ROOF: + Sequence: idle-roof + WithProductionDoorOverlay@DOOR: WithProductionOverlay@WHITELIGHTS: Sequence: production-lights-white WithProductionOverlay@REDLIGHTS: diff --git a/mods/ts/rules/nod-structures.yaml b/mods/ts/rules/nod-structures.yaml index 15118349d8..71aa3ad2e4 100644 --- a/mods/ts/rules/nod-structures.yaml +++ b/mods/ts/rules/nod-structures.yaml @@ -130,8 +130,6 @@ NAWEAP: HP: 1000 RevealsShroud: Range: 4c0 - -RenderBuilding: - RenderBuildingWarFactory: RallyPoint: RallyPoint: 6,1 Exit@1: @@ -141,6 +139,9 @@ NAWEAP: Produces: Vehicle PrimaryBuilding: ProductionBar: + WithIdleOverlay@ROOF: + Sequence: idle-roof + WithProductionDoorOverlay@DOOR: WithProductionOverlay@LIGHTS: Sequence: production-lights WithIdleOverlay@BIB: diff --git a/mods/ts/sequences/structures.yaml b/mods/ts/sequences/structures.yaml index 7deb008378..e55672301a 100644 --- a/mods/ts/sequences/structures.yaml +++ b/mods/ts/sequences/structures.yaml @@ -136,12 +136,17 @@ gaweap: Defaults: Offset: -12, -42 UseTilesetCode: true - idle: - ShadowStart: 3 - damaged-idle: + idle: gtweap_1 + ShadowStart: 2 + damaged-idle: gtweap_1 Start: 1 - ShadowStart: 4 - dead: + ShadowStart: 3 + idle-roof: gtweap_2 + ShadowStart: 2 + damaged-idle-roof: gtweap_2 + Start: 1 + ShadowStart: 3 + dead: gtweap Start: 2 ShadowStart: 5 Tick: 400 @@ -171,15 +176,12 @@ gaweap: Length: 4 Tick: 80 ZOffset: 2048 - build-top: gtweap_d + build-door: gtweap_d Length: 9 ShadowStart: 9 - damaged-build-top: gtweap_d + damaged-build-door: gtweap_d Length: 9 ShadowStart: 9 - idle-top: gtweap_2 - damaged-idle-top: gtweap_2 - Start: 1 make: gtweapmk Length: 20 Tick: 80 @@ -195,7 +197,6 @@ gaweap: icon: weapicon Offset: 0, 0 UseTilesetCode: false -# TODO: gtweap_1 & gtweap_a & gtweap_b & gtweap_c are unused napowr: Defaults: @@ -289,12 +290,17 @@ naweap: Defaults: Offset: -12, -42 UseTilesetCode: true - idle: - ShadowStart: 3 - damaged-idle: + idle: ntweap_1 + ShadowStart: 2 + damaged-idle: ntweap_1 Start: 1 - ShadowStart: 4 - dead: + ShadowStart: 3 + idle-roof: ntweap_2 + ShadowStart: 2 + damaged-idle-roof: ntweap_2 + Start: 1 + ShadowStart: 3 + dead: ntweap Start: 2 ShadowStart: 5 Tick: 400 @@ -307,16 +313,13 @@ naweap: Length: 16 Tick: 100 ZOffset: 2048 - build-top: ntweap_b + build-door: ntweap_b Length: 10 ShadowStart: 10 - damaged-build-top: ntweap_b + damaged-build-door: ntweap_b Start: 10 Length: 10 ShadowStart: 20 - idle-top: ntweap_2 - damaged-idle-top: ntweap_2 - Start: 1 make: ntweapmk Length: 22 Tick: 80 @@ -329,7 +332,6 @@ naweap: icon: nwepicon Offset: 0, 0 UseTilesetCode: false -# TODO: ntweap_1 & ntweap_b & ntweap_c are unused naradr: Defaults: