diff --git a/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs b/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs new file mode 100644 index 0000000000..db11c721fe --- /dev/null +++ b/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs @@ -0,0 +1,100 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 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.Mods.Common.Traits; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.D2k.Traits.Buildings +{ + public class D2kBuildingInfo : BuildingInfo + { + [Desc("Amount of damage received per DamageInterval ticks.")] + public readonly int Damage = 500; + + [Desc("Delay between receiving damage.")] + public readonly int DamageInterval = 100; + + [Desc("Apply the damage using these damagetypes.")] + public readonly BitSet DamageTypes = default(BitSet); + + [Desc("Terrain types where the actor will take damage.")] + public readonly string[] DamageTerrainTypes = { "Rock" }; + + [Desc("Percentage health below which the actor will not receive further damage.")] + public readonly int DamageThreshold = 50; + + [Desc("Inflict damage down to the DamageThreshold when the actor gets created on damaging terrain.")] + public readonly bool StartOnThreshold = true; + + public override object Create(ActorInitializer init) { return new D2kBuilding(init, this); } + } + + public class D2kBuilding : Building, ITick, INotifyCreated + { + readonly D2kBuildingInfo info; + IHealth health; + int safeTiles; + int totalTiles; + int damageThreshold; + int damageTicks; + + public D2kBuilding(ActorInitializer init, D2kBuildingInfo info) + : base(init, info) + { + this.info = info; + } + + void INotifyCreated.Created(Actor self) + { + health = self.TraitOrDefault(); + } + + protected override void AddedToWorld(Actor self) + { + base.AddedToWorld(self); + + if (health == null) + return; + + foreach (var kv in self.OccupiesSpace.OccupiedCells()) + { + totalTiles++; + if (!info.DamageTerrainTypes.Contains(self.World.Map.GetTerrainInfo(kv.Cell).Type)) + safeTiles++; + } + + if (totalTiles == 0 || totalTiles == safeTiles) + return; + + // Cast to long to avoid overflow when multiplying by the health + damageThreshold = (int)((info.DamageThreshold * (long)health.MaxHP + (100 - info.DamageThreshold) * safeTiles * (long)health.MaxHP / totalTiles) / 100); + + if (!info.StartOnThreshold) + return; + + // Start with maximum damage applied + var delta = health.HP - damageThreshold; + if (delta > 0) + self.InflictDamage(self.World.WorldActor, new Damage(delta, info.DamageTypes)); + } + + void ITick.Tick(Actor self) + { + if (totalTiles == safeTiles || health.HP <= damageThreshold || --damageTicks > 0) + return; + + self.InflictDamage(self.World.WorldActor, new Damage(info.Damage, info.DamageTypes)); + damageTicks = info.DamageInterval; + } + } +} diff --git a/mods/d2k/rules/arrakis.yaml b/mods/d2k/rules/arrakis.yaml index 5428d31463..40d7b8172c 100644 --- a/mods/d2k/rules/arrakis.yaml +++ b/mods/d2k/rules/arrakis.yaml @@ -134,17 +134,17 @@ sietch: Inherits: ^Building Tooltip: Name: Fremen Sietch - Building: + D2kBuilding: Footprint: xx xx Dimensions: 2,2 TerrainTypes: Cliff + DamageTerrainTypes: Health: HP: 60000 Armor: Type: wood RevealsShroud: Range: 10c0 - -DamagedByTerrain: -GivesBuildableArea: -Sellable: -Capturable: diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index 416261ae5b..385bdfa594 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -404,7 +404,7 @@ Type: Rectangle TopLeft: -512, -512 BottomRight: 512, 512 - Building: + D2kBuilding: Dimensions: 1,1 Footprint: x TerrainTypes: Rock, Concrete @@ -451,11 +451,6 @@ GrantConditionOnPrerequisite@AUTOCONCRETE: Condition: auto-concrete Prerequisites: global-auto-concrete - DamagedByTerrain: - RequiresCondition: !auto-concrete - Damage: 500 - DamageInterval: 100 - Terrain: Rock LaysTerrain: RequiresCondition: auto-concrete TerrainTypes: Rock diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index 3f6b414dab..a542e25efe 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -1,7 +1,7 @@ ^concrete: AlwaysVisible: Interactable: - Building: + D2kBuilding: TerrainTypes: Rock BuildSounds: CHUNG.WAV AllowInvalidPlacement: true @@ -25,7 +25,7 @@ concretea: Inherits: ^concrete - Building: + D2kBuilding: Footprint: xx xx Dimensions: 2,2 Tooltip: @@ -40,7 +40,7 @@ concretea: concreteb: Inherits: ^concrete - Building: + D2kBuilding: Footprint: xxx xxx xxx Dimensions: 3,3 Tooltip: @@ -59,8 +59,7 @@ construction_yard: Inherits@UPGRADEABLE: ^Upgradeable Buildable: Description: Produces structures. - -DamagedByTerrain: - Building: + D2kBuilding: Footprint: xxx xxx === Dimensions: 3,3 LocalCenterOffset: 0,-512,0 @@ -127,7 +126,7 @@ wind_trap: Cost: 225 Tooltip: Name: Wind Trap - Building: + D2kBuilding: Footprint: xx xx == Dimensions: 2,3 LocalCenterOffset: 0,-512,0 @@ -176,7 +175,7 @@ barracks: Cost: 225 Tooltip: Name: Barracks - Building: + D2kBuilding: Footprint: xx xx == Dimensions: 2,3 LocalCenterOffset: 0,-512,0 @@ -243,7 +242,7 @@ refinery: Cost: 1500 Tooltip: Name: Spice Refinery - Building: + D2kBuilding: Footprint: =xx xx= === Dimensions: 3,3 LocalCenterOffset: 0,-512,0 @@ -367,7 +366,7 @@ light_factory: Cost: 500 Tooltip: Name: Light Factory - Building: + D2kBuilding: Footprint: xxx xx= === Dimensions: 3,3 LocalCenterOffset: 0,-512,0 @@ -445,7 +444,7 @@ heavy_factory: Cost: 1000 Tooltip: Name: Heavy Factory - Building: + D2kBuilding: Footprint: _x_ xxx =xX === Dimensions: 3,4 LocalCenterOffset: 0,-512,0 @@ -533,7 +532,7 @@ outpost: Cost: 750 Tooltip: Name: Outpost - Building: + D2kBuilding: Footprint: xxx xxx === Dimensions: 3,3 LocalCenterOffset: 0,-512,0 @@ -581,7 +580,7 @@ starport: Description: Dropzone for quick reinforcements, at a price. Valued: Cost: 1500 - Building: + D2kBuilding: Footprint: xxx x=x =x= Dimensions: 3,3 Selectable: @@ -672,7 +671,7 @@ wall: Name: Concrete Wall GenericName: Structure AppearsOnRadar: - Building: + D2kBuilding: BuildSounds: CHUNG.WAV TerrainTypes: Rock, Concrete FootprintPlaceBuildingPreview: @@ -816,7 +815,7 @@ repair_pad: Cost: 800 Tooltip: Name: Repair Pad - Building: + D2kBuilding: Footprint: +++ +++ +++ Dimensions: 3,3 Health: @@ -883,7 +882,7 @@ high_tech_factory: Exit: SpawnOffset: 0,0,728 ExitCell: 0,0 - Building: + D2kBuilding: Footprint: _X_ xxx XXX === Dimensions: 3,4 LocalCenterOffset: 0,-512,0 @@ -953,7 +952,7 @@ research_centre: Cost: 1000 Tooltip: Name: IX Research Center - Building: + D2kBuilding: Footprint: _X_ xxx XXX === Dimensions: 3,4 LocalCenterOffset: 0,-512,0 @@ -1005,7 +1004,7 @@ palace: Cost: 1600 Tooltip: Name: Palace - Building: + D2kBuilding: Footprint: xx= xxx =xx Dimensions: 3,3 Health: