diff --git a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj index 92dd5fc7d9..fd3357dda1 100644 --- a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj +++ b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj @@ -78,7 +78,6 @@ - diff --git a/OpenRA.Mods.Cnc/Traits/PoisonedByTiberium.cs b/OpenRA.Mods.Cnc/Traits/PoisonedByTiberium.cs deleted file mode 100644 index e0e00986cb..0000000000 --- a/OpenRA.Mods.Cnc/Traits/PoisonedByTiberium.cs +++ /dev/null @@ -1,59 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 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, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.GameRules; -using OpenRA.Mods.Common.Traits; -using OpenRA.Traits; - -namespace OpenRA.Mods.Cnc.Traits -{ - class PoisonedByTiberiumInfo : UpgradableTraitInfo, IRulesetLoaded - { - [WeaponReference] public readonly string Weapon = "Tiberium"; - public readonly HashSet Resources = new HashSet { "Tiberium", "BlueTiberium" }; - - public WeaponInfo WeaponInfo { get; private set; } - - public override object Create(ActorInitializer init) { return new PoisonedByTiberium(init, this); } - public void RulesetLoaded(Ruleset rules, ActorInfo ai) { WeaponInfo = rules.Weapons[Weapon.ToLowerInvariant()]; } - } - - class PoisonedByTiberium : UpgradableTrait, ITick, ISync - { - readonly ResourceLayer rl; - [Sync] int poisonTicks; - - public PoisonedByTiberium(ActorInitializer init, PoisonedByTiberiumInfo info) - : base(info) - { - rl = init.Self.World.WorldActor.Trait(); - } - - public void Tick(Actor self) - { - if (IsTraitDisabled || --poisonTicks > 0) - return; - - // Prevents harming infantry in cargo. - if (!self.IsInWorld) - return; - - var r = rl.GetResource(self.Location); - if (r == null || !Info.Resources.Contains(r.Info.Name)) - return; - - Info.WeaponInfo.Impact(Target.FromActor(self), self.World.WorldActor, Enumerable.Empty()); - poisonTicks = Info.WeaponInfo.ReloadDelay; - } - } -} diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index fa44f8d02b..44835881df 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -326,6 +326,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/DamagedByTerrain.cs b/OpenRA.Mods.Common/Traits/DamagedByTerrain.cs new file mode 100644 index 0000000000..9106d4ef9f --- /dev/null +++ b/OpenRA.Mods.Common/Traits/DamagedByTerrain.cs @@ -0,0 +1,90 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("This actor receives damage from the given weapon when on the specified terrain type.")] + class DamagedByTerrainInfo : UpgradableTraitInfo, IRulesetLoaded, Requires + { + [Desc("The weapon which is used to damage the actor.")] + [WeaponReference, FieldLoader.Require] public readonly string Weapon; + + [Desc("Terrain types where the actor will take damage.")] + [FieldLoader.Require] public readonly string[] Terrain = { }; + + [Desc("Percentage health below which the actor will not receive further damage.")] + public readonly int DamageThreshold = 0; + + [Desc("Inflict damage down to the DamageThreshold when the actor gets created on damaging terrain.")] + public readonly bool StartOnThreshold = false; + + public WeaponInfo WeaponInfo { get; private set; } + + public override object Create(ActorInitializer init) { return new DamagedByTerrain(init.Self, this); } + public void RulesetLoaded(Ruleset rules, ActorInfo ai) { WeaponInfo = rules.Weapons[Weapon.ToLowerInvariant()]; } + } + + class DamagedByTerrain : UpgradableTrait, ITick, ISync, INotifyAddedToWorld + { + readonly Health health; + + [Sync] int damageTicks; + [Sync] int damageThreshold; + + public DamagedByTerrain(Actor self, DamagedByTerrainInfo info) : base(info) + { + health = self.Trait(); + } + + public void AddedToWorld(Actor self) + { + if (!Info.StartOnThreshold) + return; + + var safeTiles = 0; + var totalTiles = 0; + foreach (var kv in self.OccupiesSpace.OccupiedCells()) + { + totalTiles++; + if (!Info.Terrain.Contains(self.World.Map.GetTerrainInfo(kv.First).Type)) + safeTiles++; + } + + damageThreshold = (Info.DamageThreshold * health.MaxHP + (100 - Info.DamageThreshold) * safeTiles * health.MaxHP / totalTiles) / 100; + + // Actors start with maximum damage applied + var delta = health.HP - damageThreshold; + if (delta > 0) + health.InflictDamage(self, self.World.WorldActor, delta, null, false); + } + + public void Tick(Actor self) + { + if (IsTraitDisabled || health.HP <= damageThreshold || --damageTicks > 0) + return; + + // Prevents harming cargo. + if (!self.IsInWorld) + return; + + var t = self.World.Map.GetTerrainInfo(self.Location); + if (!Info.Terrain.Contains(t.Type)) + return; + + Info.WeaponInfo.Impact(Target.FromActor(self), self.World.WorldActor, Enumerable.Empty()); + damageTicks = Info.WeaponInfo.ReloadDelay; + } + } +} diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 48aebb832f..517fd62a40 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -222,6 +222,40 @@ namespace OpenRA.Mods.Common.UtilityCommands } } + if (engineVersion < 20160704) + { + if (node.Key.Contains("PoisonedByTiberium")) + { + node.Key = node.Key.Replace("PoisonedByTiberium", "DamagedByTerrain"); + if (!node.Key.StartsWith("-")) + { + if (node.Value.Nodes.Any(a => a.Key == "Resources")) + node.Value.Nodes.Where(n => n.Key == "Resources").Do(n => n.Key = "Terrain"); + else + node.Value.Nodes.Add(new MiniYamlNode("Terrain", new MiniYaml("Tiberium, BlueTiberium"))); + + if (!node.Value.Nodes.Any(a => a.Key == "Weapon")) + node.Value.Nodes.Add(new MiniYamlNode("Weapon", new MiniYaml("Tiberium"))); + } + } + + if (node.Key.Contains("DamagedWithoutFoundation")) + { + node.Key = node.Key.Replace("DamagedWithoutFoundation", "DamagedByTerrain"); + if (!node.Key.StartsWith("-")) + { + if (!node.Value.Nodes.Any(a => a.Key == "Weapon")) + node.Value.Nodes.Add(new MiniYamlNode("Weapon", new MiniYaml("weathering"))); + + Console.WriteLine("SafeTerrain isn't converted. Setup an inverted check using Terrain."); + + node.Value.Nodes.Add(new MiniYamlNode("StartOnThreshold", new MiniYaml("true"))); + if (!node.Value.Nodes.Any(a => a.Key == "DamageThreshold")) + node.Value.Nodes.Add(new MiniYamlNode("DamageThreshold", new MiniYaml("50"))); + } + } + } + UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1); } diff --git a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj index 1f1107c965..7baf4c5cc0 100644 --- a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj +++ b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj @@ -79,7 +79,6 @@ - diff --git a/OpenRA.Mods.D2k/Traits/Buildings/DamagedWithoutFoundation.cs b/OpenRA.Mods.D2k/Traits/Buildings/DamagedWithoutFoundation.cs deleted file mode 100644 index 162bf05048..0000000000 --- a/OpenRA.Mods.D2k/Traits/Buildings/DamagedWithoutFoundation.cs +++ /dev/null @@ -1,85 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 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, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.GameRules; -using OpenRA.Mods.Common.Traits; -using OpenRA.Traits; - -namespace OpenRA.Mods.D2k.Traits -{ - [Desc("Reduces health points over time when the actor is placed on unsafe terrain.")] - class DamagedWithoutFoundationInfo : ITraitInfo, IRulesetLoaded, Requires - { - [WeaponReference, Desc("The weapon to use for causing damage.")] - public readonly string Weapon = "weathering"; - - [Desc("Terrain types on which no damage is caused.")] - public readonly HashSet SafeTerrain = new HashSet { "Concrete" }; - - [Desc("The percentage of health the actor should keep.")] - public readonly int DamageThreshold = 50; - - public WeaponInfo WeaponInfo { get; private set; } - - public object Create(ActorInitializer init) { return new DamagedWithoutFoundation(init.Self, this); } - public void RulesetLoaded(Ruleset rules, ActorInfo ai) { WeaponInfo = rules.Weapons[Weapon.ToLowerInvariant()]; } - } - - class DamagedWithoutFoundation : ITick, ISync, INotifyAddedToWorld - { - readonly DamagedWithoutFoundationInfo info; - readonly Health health; - - [Sync] int damageThreshold = 100; - [Sync] int damageTicks; - - public DamagedWithoutFoundation(Actor self, DamagedWithoutFoundationInfo info) - { - this.info = info; - health = self.Trait(); - } - - public void AddedToWorld(Actor self) - { - var safeTiles = 0; - var totalTiles = 0; - foreach (var kv in self.OccupiesSpace.OccupiedCells()) - { - totalTiles++; - if (info.SafeTerrain.Contains(self.World.Map.GetTerrainInfo(kv.First).Type)) - safeTiles++; - } - - if (totalTiles > 0) - damageThreshold = (info.DamageThreshold * health.MaxHP + (100 - info.DamageThreshold) * safeTiles * health.MaxHP / totalTiles) / 100; - else - damageThreshold = health.HP; - - // Actors start with maximum damage applied - var delta = health.HP - damageThreshold; - if (delta > 0) - health.InflictDamage(self, self.World.WorldActor, delta, null, false); - - damageTicks = info.WeaponInfo.ReloadDelay; - } - - public void Tick(Actor self) - { - if (health.HP <= damageThreshold || --damageTicks > 0) - return; - - info.WeaponInfo.Impact(Target.FromActor(self), self.World.WorldActor, Enumerable.Empty()); - damageTicks = info.WeaponInfo.ReloadDelay; - } - } -} diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index ef6472da97..7169d0ca4d 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -210,9 +210,11 @@ Passenger: CargoType: Infantry HiddenUnderFog: - PoisonedByTiberium: + DamagedByTerrain: UpgradeTypes: hazmatsuits UpgradeMaxEnabledLevel: 0 + Terrain: Tiberium, BlueTiberium + Weapon: Tiberium GlobalUpgradable@BIO: Upgrades: hazmatsuits Prerequisites: bio @@ -416,8 +418,9 @@ Guard: Voice: Move Guardable: - PoisonedByTiberium: + DamagedByTerrain: Weapon: Heal + Terrain: Tiberium, BlueTiberium Voiced: VoiceSet: DinoVoice diff --git a/mods/cnc/rules/infantry.yaml b/mods/cnc/rules/infantry.yaml index defa48affd..7e035b835e 100644 --- a/mods/cnc/rules/infantry.yaml +++ b/mods/cnc/rules/infantry.yaml @@ -122,7 +122,7 @@ E5: MuzzleSequence: muzzle AttackFrontal: WithMuzzleOverlay: - -PoisonedByTiberium: + -DamagedByTerrain: WithInfantryBody: AttackSequence: shoot diff --git a/mods/d2k/rules/arrakis.yaml b/mods/d2k/rules/arrakis.yaml index 95419fec35..bbd288b957 100644 --- a/mods/d2k/rules/arrakis.yaml +++ b/mods/d2k/rules/arrakis.yaml @@ -125,7 +125,7 @@ sietch: Type: wood RevealsShroud: Range: 10c0 - -DamagedWithoutFoundation: + -DamagedByTerrain: -GivesBuildableArea: -Sellable: -Capturable: diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index 63c8da3750..c11436f09e 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -277,7 +277,11 @@ Range: 3c0 WithCrumbleOverlay: Demolishable: - DamagedWithoutFoundation: + DamagedByTerrain: + Weapon: weathering + Terrain: Rock + DamageThreshold: 50 + StartOnThreshold: true ThrowsShrapnel: Weapons: Debris, Debris2, Debris3, Debris4 Pieces: 2, 5 diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index 9de2511fdb..5c3b8f7842 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -43,7 +43,7 @@ concreteb: construction_yard: Inherits: ^Building - -DamagedWithoutFoundation: + -DamagedByTerrain: Building: Footprint: xxx xxx Dimensions: 3,2 diff --git a/mods/ts/rules/civilian-infantry.yaml b/mods/ts/rules/civilian-infantry.yaml index d374b5a2e6..7cb1ba4291 100644 --- a/mods/ts/rules/civilian-infantry.yaml +++ b/mods/ts/rules/civilian-infantry.yaml @@ -35,8 +35,9 @@ UMAGON: Speed: 71 Health: HP: 150 - PoisonedByTiberium: + DamagedByTerrain: Weapon: TiberiumHeal + Terrain: Tiberium, BlueTiberium Passenger: RevealsShroud: Range: 7c0 @@ -90,8 +91,9 @@ MUTANT: VoiceSet: Mutant Health: HP: 50 - PoisonedByTiberium: + DamagedByTerrain: Weapon: TiberiumHeal + Terrain: Tiberium, BlueTiberium Mobile: Speed: 56 RevealsShroud: @@ -115,8 +117,9 @@ MWMN: VoiceSet: CivilianFemale Health: HP: 50 - PoisonedByTiberium: + DamagedByTerrain: Weapon: TiberiumHeal + Terrain: Tiberium, BlueTiberium Mobile: Speed: 56 RevealsShroud: @@ -140,8 +143,9 @@ MUTANT3: VoiceSet: Mutant Health: HP: 50 - PoisonedByTiberium: + DamagedByTerrain: Weapon: TiberiumHeal + Terrain: Tiberium, BlueTiberium Mobile: Speed: 56 RevealsShroud: @@ -165,8 +169,9 @@ TRATOS: VoiceSet: Tratos Health: HP: 200 - PoisonedByTiberium: + DamagedByTerrain: Weapon: TiberiumHeal + Terrain: Tiberium, BlueTiberium Mobile: Speed: 71 RevealsShroud: @@ -220,8 +225,9 @@ DOGGIE: HP: 250 Shape: Circle Radius: 213 - PoisonedByTiberium: + DamagedByTerrain: Weapon: TiberiumHeal + Terrain: Tiberium, BlueTiberium Valued: Cost: 100 Armor: diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml index a69d65fd21..e410bfcbd0 100644 --- a/mods/ts/rules/defaults.yaml +++ b/mods/ts/rules/defaults.yaml @@ -284,7 +284,9 @@ Voice: Move HiddenUnderFog: ActorLostNotification: - PoisonedByTiberium: + DamagedByTerrain: + Terrain: Tiberium, BlueTiberium + Weapon: Tiberium Guard: Voice: Move Guardable: @@ -383,8 +385,9 @@ RevealsShroud: Range: 4c0 MustBeDestroyed: - PoisonedByTiberium: + DamagedByTerrain: Weapon: TiberiumHeal + Terrain: Tiberium, BlueTiberium WithPermanentInjury: WithInfantryBody: AttackSequence: attack @@ -465,9 +468,9 @@ Weapons: SmallDebris Pieces: 3, 7 Range: 2c0, 5c0 - PoisonedByTiberium: + DamagedByTerrain: Weapon: Veins - Resources: Veins + Terrain: Veins UpgradeOnDamage@DAMAGED: Upgrades: damagedspeed ValidDamageStates: Heavy @@ -633,8 +636,9 @@ TargetTypes: Ground, Creep AttackMove: HiddenUnderFog: - PoisonedByTiberium: + DamagedByTerrain: Weapon: TiberiumHeal + Terrain: Tiberium, BlueTiberium Guardable: WithSpriteBody: diff --git a/mods/ts/rules/gdi-infantry.yaml b/mods/ts/rules/gdi-infantry.yaml index 46b3d86c31..e5db95918b 100644 --- a/mods/ts/rules/gdi-infantry.yaml +++ b/mods/ts/rules/gdi-infantry.yaml @@ -113,8 +113,9 @@ GHOST: Speed: 56 Health: HP: 200 - PoisonedByTiberium: + DamagedByTerrain: Weapon: TiberiumHeal + Terrain: Tiberium, BlueTiberium Passenger: RevealsShroud: Range: 6c0 diff --git a/mods/ts/rules/gdi-vehicles.yaml b/mods/ts/rules/gdi-vehicles.yaml index d8b40033ab..dfbb422685 100644 --- a/mods/ts/rules/gdi-vehicles.yaml +++ b/mods/ts/rules/gdi-vehicles.yaml @@ -93,7 +93,7 @@ HVR: TrailWhileStationary: True StationaryInterval: 18 MovingInterval: 6 - -PoisonedByTiberium: + -DamagedByTerrain: SMECH: Inherits: ^Vehicle @@ -132,7 +132,7 @@ SMECH: MoveSequence: run Selectable: Bounds: 20, 32, 0, -8 - -PoisonedByTiberium: + -DamagedByTerrain: MMCH: Inherits: ^Tank diff --git a/mods/ts/rules/nod-infantry.yaml b/mods/ts/rules/nod-infantry.yaml index 59fc9cd028..c9409b8422 100644 --- a/mods/ts/rules/nod-infantry.yaml +++ b/mods/ts/rules/nod-infantry.yaml @@ -109,8 +109,9 @@ MHIJACK: VoiceSet: Hijacker Health: HP: 300 - PoisonedByTiberium: + DamagedByTerrain: Weapon: TiberiumHeal + Terrain: Tiberium, BlueTiberium Mobile: Speed: 99 -Crushable: diff --git a/mods/ts/rules/nod-vehicles.yaml b/mods/ts/rules/nod-vehicles.yaml index d9c04b2ceb..2a73f78185 100644 --- a/mods/ts/rules/nod-vehicles.yaml +++ b/mods/ts/rules/nod-vehicles.yaml @@ -27,7 +27,7 @@ BGGY: Voice: Attack AutoTarget: WithMuzzleOverlay: - -PoisonedByTiberium: + -DamagedByTerrain: BIKE: Inherits: ^VoxelVehicle @@ -257,7 +257,7 @@ WEED: -WithVoxelBody: WithVoxelUnloadBody: -GainsExperience: - -PoisonedByTiberium: + -DamagedByTerrain: SAPC: Inherits: ^VoxelTank diff --git a/mods/ts/rules/shared-vehicles.yaml b/mods/ts/rules/shared-vehicles.yaml index 7ff3527ad0..30e6fe1337 100644 --- a/mods/ts/rules/shared-vehicles.yaml +++ b/mods/ts/rules/shared-vehicles.yaml @@ -96,7 +96,7 @@ HARV: FactionImages: gdi: harv.gdi nod: harv.nod - -PoisonedByTiberium: + -DamagedByTerrain: LPST: Inherits: ^VoxelTank