From 07947179cde033c4182b48040412f0fda9719dce Mon Sep 17 00:00:00 2001 From: Pavel Penev Date: Sat, 13 Feb 2016 18:46:42 +0200 Subject: [PATCH 1/5] Don't crash on multiple Attack* traits This is important for actors that use upgrades to switch between attack types. --- OpenRA.Mods.Common/Activities/Attack.cs | 45 ++++++++++++++++--- .../Traits/CombatDebugOverlay.cs | 20 ++++----- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/OpenRA.Mods.Common/Activities/Attack.cs b/OpenRA.Mods.Common/Activities/Attack.cs index 8d164ee376..bf8ab5eb35 100644 --- a/OpenRA.Mods.Common/Activities/Attack.cs +++ b/OpenRA.Mods.Common/Activities/Attack.cs @@ -8,6 +8,7 @@ */ #endregion +using System; using System.Linq; using OpenRA.Activities; using OpenRA.Mods.Common.Traits; @@ -18,8 +19,11 @@ namespace OpenRA.Mods.Common.Activities /* non-turreted attack */ public class Attack : Activity { + [Flags] + enum AttackStatus { UnableToAttack, NeedsToTurn, NeedsToMove, Attacking } + protected readonly Target Target; - readonly AttackBase attack; + readonly AttackBase[] attackTraits; readonly IMove move; readonly IFacing facing; readonly IPositionable positionable; @@ -27,6 +31,9 @@ namespace OpenRA.Mods.Common.Activities WDist minRange; WDist maxRange; + Activity turnActivity; + Activity moveActivity; + AttackStatus attackStatus = AttackStatus.UnableToAttack; public Attack(Actor self, Target target, bool allowMovement, bool forceAttack) { @@ -34,7 +41,7 @@ namespace OpenRA.Mods.Common.Activities this.forceAttack = forceAttack; - attack = self.Trait(); + attackTraits = self.TraitsImplementing().ToArray(); facing = self.Trait(); positionable = self.Trait(); @@ -43,9 +50,25 @@ namespace OpenRA.Mods.Common.Activities public override Activity Tick(Actor self) { - var ret = InnerTick(self, attack); - attack.IsAttacking = ret == this; - return ret; + turnActivity = moveActivity = null; + attackStatus = AttackStatus.UnableToAttack; + + foreach (var attack in attackTraits.Where(x => !x.IsTraitDisabled)) + { + var activity = InnerTick(self, attack); + attack.IsAttacking = activity == this; + } + + if (attackStatus.HasFlag(AttackStatus.Attacking)) + return this; + + if (attackStatus.HasFlag(AttackStatus.NeedsToTurn)) + return turnActivity; + + if (attackStatus.HasFlag(AttackStatus.NeedsToMove)) + return moveActivity; + + return NextActivity; } protected virtual Activity InnerTick(Actor self, AttackBase attack) @@ -81,13 +104,21 @@ namespace OpenRA.Mods.Common.Activities // Try to move within range, drop the target otherwise if (move == null) return NextActivity; - return ActivityUtils.SequenceActivities(move.MoveWithinRange(Target, minRange, maxRange), this); + + attackStatus |= AttackStatus.NeedsToMove; + moveActivity = ActivityUtils.SequenceActivities(move.MoveWithinRange(Target, minRange, maxRange), this); + return NextActivity; } var desiredFacing = (Target.CenterPosition - self.CenterPosition).Yaw.Facing; if (facing.Facing != desiredFacing) - return ActivityUtils.SequenceActivities(new Turn(self, desiredFacing), this); + { + attackStatus |= AttackStatus.NeedsToTurn; + turnActivity = ActivityUtils.SequenceActivities(new Turn(self, desiredFacing), this); + return NextActivity; + } + attackStatus |= AttackStatus.Attacking; attack.DoAttack(self, Target, armaments); return this; diff --git a/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs b/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs index 72d30fdbea..23203fa42c 100644 --- a/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs +++ b/OpenRA.Mods.Common/Traits/CombatDebugOverlay.cs @@ -27,17 +27,15 @@ namespace OpenRA.Mods.Common.Traits public class CombatDebugOverlay : IPostRender, INotifyDamage, INotifyCreated { readonly DeveloperMode devMode; - readonly HealthInfo healthInfo; + readonly Lazy coords; + IBlocksProjectiles[] allBlockers; - Lazy attack; - Lazy coords; public CombatDebugOverlay(Actor self) { healthInfo = self.Info.TraitInfoOrDefault(); - attack = Exts.Lazy(() => self.TraitOrDefault()); - coords = Exts.Lazy(() => self.Trait()); + coords = Exts.Lazy(self.Trait); var localPlayer = self.World.LocalPlayer; devMode = localPlayer != null ? localPlayer.PlayerActor.Trait() : null; @@ -71,14 +69,16 @@ namespace OpenRA.Mods.Common.Traits TargetLineRenderable.DrawTargetMarker(wr, hc, hb); } - // No armaments to draw - if (attack.Value == null) - return; + foreach (var attack in self.TraitsImplementing().Where(x => !x.IsTraitDisabled)) + DrawArmaments(self, attack, wr, wcr, iz); + } + void DrawArmaments(Actor self, AttackBase attack, WorldRenderer wr, RgbaColorRenderer wcr, float iz) + { var c = Color.White; // Fire ports on garrisonable structures - var garrison = attack.Value as AttackGarrisoned; + var garrison = attack as AttackGarrisoned; if (garrison != null) { var bodyOrientation = coords.Value.QuantizeOrientation(self, self.Orientation); @@ -98,7 +98,7 @@ namespace OpenRA.Mods.Common.Traits return; } - foreach (var a in attack.Value.Armaments) + foreach (var a in attack.Armaments) { foreach (var b in a.Barrels) { From 99afec6533638a52e015d62e3a47cf3eb7f833c9 Mon Sep 17 00:00:00 2001 From: Pavel Penev Date: Sat, 13 Feb 2016 19:45:30 +0200 Subject: [PATCH 2/5] Convert the Tick Tank to use DeployToUpgrade --- mods/ts/rules/nod-vehicles.yaml | 71 +++++++++++++++++++++++++++++---- mods/ts/sequences/vehicles.yaml | 11 +++++ mods/ts/sequences/voxels.yaml | 2 - 3 files changed, 74 insertions(+), 10 deletions(-) diff --git a/mods/ts/rules/nod-vehicles.yaml b/mods/ts/rules/nod-vehicles.yaml index d6944d5d15..105b45ec08 100644 --- a/mods/ts/rules/nod-vehicles.yaml +++ b/mods/ts/rules/nod-vehicles.yaml @@ -82,8 +82,8 @@ TTNK: HP: 350 Armor: Type: Light - AttackFrontal: - Voice: Attack + UpgradeTypes: undeployed + UpgradeMinEnabledLevel: 1 Armament@PRIMARY: Weapon: 90mm LocalOffset: 256,0,256 @@ -100,12 +100,67 @@ TTNK: WithMuzzleOverlay: RevealsShroud: Range: 5c0 - Transforms: - IntoActor: gatick - Facing: 159 - TransformSounds: place2.aud - NoTransformSounds: - Voice: Move + RenderSprites: + Image: ttnk + DeployToUpgrade: + DeployedUpgrades: deployed, notmobile + UndeployedUpgrades: undeployed + DeployAnimation: make + Facing: 160 + AllowedTerrainTypes: Clear, Road, DirtRoad, Rough + DeploySound: place2.aud + UndeploySound: clicky1.aud + WithVoxelBody: + UpgradeTypes: undeployed + UpgradeMinEnabledLevel: 1 + WithSpriteBody@deployed: + UpgradeTypes: undeployed + UpgradeMaxEnabledLevel: 0 + AttackFrontal: + Voice: Attack + UpgradeTypes: undeployed + UpgradeMinEnabledLevel: 1 + UpgradeMaxAcceptedLevel: 1 + Turreted: + ROT: 6 + Turret: deployed + InitialFacing: 128 + Offset: -20, -130, 180 + WithVoxelBarrel: + Armament: deployed + LocalOffset: 128, 0, 256 + UpgradeTypes: deployed + UpgradeMinEnabledLevel: 1 + WithVoxelTurret@deployed: + Turret: deployed + UpgradeTypes: deployed + UpgradeMinEnabledLevel: 1 + AttackTurreted@deployed: + Voice: Attack + Armaments: deployed + UpgradeTypes: deployed + UpgradeMinEnabledLevel: 1 + Armament@deployed: + Name: deployed + Turret: deployed + Weapon: 90mm + LocalOffset: 384,0,256 + UpgradeTypes: eliteweapon + UpgradeMaxEnabledLevel: 0 + UpgradeMaxAcceptedLevel: 1 + MuzzleSequence: muzzle + Armament@deployedElite: + Name: deployed + Turret: deployed + Weapon: 120mmx + LocalOffset: 384,0,256 + UpgradeTypes: eliteweapon + UpgradeMinEnabledLevel: 1 + MuzzleSequence: muzzle + Armor@deployed: + Type: Concrete + UpgradeTypes: deployed + UpgradeMinEnabledLevel: 1 ART2: Inherits: ^VoxelTank diff --git a/mods/ts/sequences/vehicles.yaml b/mods/ts/sequences/vehicles.yaml index 753bc8a19f..eadef7b244 100644 --- a/mods/ts/sequences/vehicles.yaml +++ b/mods/ts/sequences/vehicles.yaml @@ -135,6 +135,17 @@ sonic: icon: soniicon ttnk: + idle: gatick + ShadowStart: 3 + Offset: 0, -12 + damaged-idle: gatick + Start: 1 + ShadowStart: 4 + Offset: 0, -12 + make: gatickmk + Length: 24 + ShadowStart: 24 + Offset: 0, -12 muzzle: gunfire Length: * emp-overlay: emp_fx01 diff --git a/mods/ts/sequences/voxels.yaml b/mods/ts/sequences/voxels.yaml index fa919c83ec..3b16296652 100644 --- a/mods/ts/sequences/voxels.yaml +++ b/mods/ts/sequences/voxels.yaml @@ -33,8 +33,6 @@ bike: ttnk: idle: - -gatick: turret: ttnktur barrel: ttnkbarl From ba0781c28d5a66321f5a20fa644b173d1a54155d Mon Sep 17 00:00:00 2001 From: Pavel Penev Date: Sat, 13 Feb 2016 19:46:52 +0200 Subject: [PATCH 3/5] Remove now-redundant actor `gatick` (deployed tick tank) --- mods/ts/rules/nod-support.yaml | 43 ------------------------------- mods/ts/sequences/structures.yaml | 23 ----------------- 2 files changed, 66 deletions(-) diff --git a/mods/ts/rules/nod-support.yaml b/mods/ts/rules/nod-support.yaml index 3aa53567ee..b1c9a20f70 100644 --- a/mods/ts/rules/nod-support.yaml +++ b/mods/ts/rules/nod-support.yaml @@ -163,49 +163,6 @@ NASAM: SelectionDecorations: VisualBounds: 40, 36, -3, -8 -GATICK: - Inherits: ^DeployedVehicle - Valued: - Cost: 800 - Tooltip: - Name: Tick Tank - Health: - HP: 350 - Armor: - Type: Concrete - RevealsShroud: - Range: 5c0 - Turreted: - ROT: 6 - InitialFacing: 224 - Offset: 0,96,224 - Armament@PRIMARY: - Weapon: 90mm - LocalOffset: 448,0,348 - UpgradeTypes: eliteweapon - UpgradeMaxEnabledLevel: 0 - UpgradeMaxAcceptedLevel: 1 - MuzzleSequence: muzzle - Armament@ELITE: - Weapon: 120mmx - LocalOffset: 448,0,348 - UpgradeTypes: eliteweapon - UpgradeMinEnabledLevel: 1 - MuzzleSequence: muzzle - BodyOrientation: - QuantizedFacings: 32 - RenderVoxels: - WithVoxelBarrel: - LocalOffset: 128,0,348 - WithVoxelTurret: - Transforms: - IntoActor: ttnk - Facing: 159 - TransformSounds: place2.aud - NoTransformSounds: - Voice: Move - WithMuzzleOverlay: - GAARTY: Inherits@1: ^DeployedVehicle Valued: diff --git a/mods/ts/sequences/structures.yaml b/mods/ts/sequences/structures.yaml index 10ee981ff3..4585647479 100644 --- a/mods/ts/sequences/structures.yaml +++ b/mods/ts/sequences/structures.yaml @@ -735,29 +735,6 @@ nawall: Offset: 0, 0 UseTilesetCode: false -gatick: - Defaults: - Offset: 0, -13 - UseTilesetCode: true - idle: - ShadowStart: 3 - damaged-idle: - Start: 1 - ShadowStart: 4 - muzzle: gunfire - Length: * - Offset: 0, 0 - UseTilesetCode: false - emp-overlay: emp_fx01 - Length: * - Offset: 0, 0 - UseTilesetCode: false - ZOffset: 512 - BlendMode: Additive - make: gatickmk - Length: 24 - ShadowStart: 24 - gaicbm: Defaults: Offset: 0, -12 From 17ef6efefc554e4e71dca43dac2ef99e031f436a Mon Sep 17 00:00:00 2001 From: Pavel Penev Date: Sat, 13 Feb 2016 19:49:43 +0200 Subject: [PATCH 4/5] Fix AttackFollow (and consequently AttackTurreted) firing at old target when the trait is reenabled Most noticeable by ordering a deployed Tick Tank to fire at the ground, then undeploying it and deploying it again. --- OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs b/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs index c9686ff459..d6611aba38 100644 --- a/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs +++ b/OpenRA.Mods.Common/Traits/Attack/AttackFollow.cs @@ -30,6 +30,12 @@ namespace OpenRA.Mods.Common.Traits public virtual void Tick(Actor self) { + if (IsTraitDisabled) + { + Target = Target.Invalid; + return; + } + DoAttack(self, Target); IsAttacking = Target.IsValidFor(self); } From 118d015e4de35846ad0a6950da7b3ddc9fb38219 Mon Sep 17 00:00:00 2001 From: Pavel Penev Date: Mon, 22 Feb 2016 02:39:59 +0200 Subject: [PATCH 5/5] Make the TS map importer aware of deployable actors who use upgrades instead of transforming --- .../UtilityCommands/ImportTSMapCommand.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs b/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs index 85582237a1..68693e8007 100644 --- a/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs +++ b/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs @@ -149,6 +149,12 @@ namespace OpenRA.Mods.TS.UtilityCommands { 0x03, new byte[] { 0x7E } } }; + private static readonly Dictionary DeployableActors = new Dictionary() + { + { "gadpsa", "lpst" }, + { "gatick", "ttnk" } + }; + [Desc("FILENAME", "Convert a Tiberian Sun map to the OpenRA format.")] public void Run(ModData modData, string[] args) { @@ -387,9 +393,17 @@ namespace OpenRA.Mods.TS.UtilityCommands var structuresSection = file.GetSection(type, true); foreach (var kv in structuresSection) { + var isDeployed = false; var entries = kv.Value.Split(','); var name = entries[1].ToLowerInvariant(); + + if (DeployableActors.ContainsKey(name)) + { + name = DeployableActors[name]; + isDeployed = true; + } + var health = short.Parse(entries[2]); var rx = int.Parse(entries[3]); var ry = int.Parse(entries[4]); @@ -407,6 +421,9 @@ namespace OpenRA.Mods.TS.UtilityCommands new FacingInit(facing), }; + if (isDeployed) + ar.Add(new DeployStateInit(DeployState.Deployed)); + if (!map.Rules.Actors.ContainsKey(name)) Console.WriteLine("Ignoring unknown actor type: `{0}`".F(name)); else