using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Prototypes; namespace Content.IntegrationTests.Tests.Damageable { [TestFixture] [TestOf(typeof(DamageableComponent))] [TestOf(typeof(DamageableSystem))] public sealed class DamageableTest { private const string TestDamageableEntityId = "TestDamageableEntityId"; private const string TestGroup1 = "TestGroup1"; private const string TestGroup2 = "TestGroup2"; private const string TestGroup3 = "TestGroup3"; private const string TestDamage1 = "TestDamage1"; private const string TestDamage2a = "TestDamage2a"; private const string TestDamage2b = "TestDamage2b"; private const string TestDamage3a = "TestDamage3a"; private const string TestDamage3b = "TestDamage3b"; private const string TestDamage3c = "TestDamage3c"; [TestPrototypes] private const string Prototypes = $@" # Define some damage groups - type: damageType id: {TestDamage1} name: damage-type-blunt - type: damageType id: {TestDamage2a} name: damage-type-blunt - type: damageType id: {TestDamage2b} name: damage-type-blunt - type: damageType id: {TestDamage3a} name: damage-type-blunt - type: damageType id: {TestDamage3b} name: damage-type-blunt - type: damageType id: {TestDamage3c} name: damage-type-blunt # Define damage Groups with 1,2,3 damage types - type: damageGroup id: {TestGroup1} name: damage-group-brute damageTypes: - {TestDamage1} - type: damageGroup id: {TestGroup2} name: damage-group-brute damageTypes: - {TestDamage2a} - {TestDamage2b} - type: damageGroup id: {TestGroup3} name: damage-group-brute damageTypes: - {TestDamage3a} - {TestDamage3b} - {TestDamage3c} # This container should not support TestDamage1 or TestDamage2b - type: damageContainer id: testDamageContainer supportedGroups: - {TestGroup3} supportedTypes: - {TestDamage2a} - type: entity id: {TestDamageableEntityId} name: {TestDamageableEntityId} components: - type: Damageable damageContainer: testDamageContainer "; [Test] public async Task TestDamageableComponents() { await using var pair = await PoolManager.GetServerClient(); var server = pair.Server; var sEntityManager = server.ResolveDependency(); var sMapManager = server.ResolveDependency(); var sPrototypeManager = server.ResolveDependency(); var sEntitySystemManager = server.ResolveDependency(); EntityUid sDamageableEntity = default; DamageableComponent sDamageableComponent = null; DamageableSystem sDamageableSystem = null; DamageGroupPrototype group1 = default!; DamageGroupPrototype group2 = default!; DamageGroupPrototype group3 = default!; DamageTypePrototype type1 = default!; DamageTypePrototype type2a = default!; DamageTypePrototype type2b = default!; DamageTypePrototype type3a = default!; DamageTypePrototype type3b = default!; DamageTypePrototype type3c = default!; FixedPoint2 typeDamage; var map = await pair.CreateTestMap(); await server.WaitPost(() => { var coordinates = map.MapCoords; sDamageableEntity = sEntityManager.SpawnEntity(TestDamageableEntityId, coordinates); sDamageableComponent = sEntityManager.GetComponent(sDamageableEntity); sDamageableSystem = sEntitySystemManager.GetEntitySystem(); group1 = sPrototypeManager.Index(TestGroup1); group2 = sPrototypeManager.Index(TestGroup2); group3 = sPrototypeManager.Index(TestGroup3); type1 = sPrototypeManager.Index(TestDamage1); type2a = sPrototypeManager.Index(TestDamage2a); type2b = sPrototypeManager.Index(TestDamage2b); type3a = sPrototypeManager.Index(TestDamage3a); type3b = sPrototypeManager.Index(TestDamage3b); type3c = sPrototypeManager.Index(TestDamage3c); }); await server.WaitRunTicks(5); await server.WaitAssertion(() => { var uid = sDamageableEntity; // Check that the correct types are supported. Assert.Multiple(() => { Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type1.ID), Is.False); Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type2a.ID), Is.True); Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type2b.ID), Is.False); Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type3a.ID), Is.True); Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type3b.ID), Is.True); Assert.That(sDamageableComponent.Damage.DamageDict.ContainsKey(type3c.ID), Is.True); }); // Check that damage is evenly distributed over a group if its a nice multiple var types = group3.DamageTypes; var damageToDeal = FixedPoint2.New(types.Count * 5); DamageSpecifier damage = new(group3, damageToDeal); sDamageableSystem.TryChangeDamage(uid, damage, true); Assert.Multiple(() => { Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damageToDeal)); Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(damageToDeal)); foreach (var type in types) { Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type, out typeDamage)); Assert.That(typeDamage, Is.EqualTo(damageToDeal / types.Count)); } }); // Heal sDamageableSystem.TryChangeDamage(uid, -damage); Assert.Multiple(() => { Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(FixedPoint2.Zero)); foreach (var type in types) { Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type, out typeDamage)); Assert.That(typeDamage, Is.EqualTo(FixedPoint2.Zero)); } }); // Check that damage works properly if it is NOT perfectly divisible among group members types = group3.DamageTypes; Assert.That(types, Has.Count.EqualTo(3)); damage = new DamageSpecifier(group3, 14); sDamageableSystem.TryChangeDamage(uid, damage, true); Assert.Multiple(() => { Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(14))); Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(FixedPoint2.New(14))); Assert.That(sDamageableComponent.Damage.DamageDict[type3a.ID], Is.EqualTo(FixedPoint2.New(4.66f))); Assert.That(sDamageableComponent.Damage.DamageDict[type3b.ID], Is.EqualTo(FixedPoint2.New(4.67f))); Assert.That(sDamageableComponent.Damage.DamageDict[type3c.ID], Is.EqualTo(FixedPoint2.New(4.67f))); }); // Heal sDamageableSystem.TryChangeDamage(uid, -damage); Assert.Multiple(() => { Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(FixedPoint2.Zero)); foreach (var type in types) { Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type, out typeDamage)); Assert.That(typeDamage, Is.EqualTo(FixedPoint2.Zero)); } // Test that unsupported groups return false when setting/getting damage (and don't change damage) Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); }); damage = new DamageSpecifier(group1, FixedPoint2.New(10)) + new DamageSpecifier(type2b, FixedPoint2.New(10)); sDamageableSystem.TryChangeDamage(uid, damage, true); Assert.Multiple(() => { Assert.That(sDamageableComponent.DamagePerGroup.TryGetValue(group1.ID, out _), Is.False); Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type1.ID, out typeDamage), Is.False); Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); }); // Test SetAll function sDamageableSystem.SetAllDamage(sDamageableEntity, sDamageableComponent, 10); Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(10 * sDamageableComponent.Damage.DamageDict.Count))); sDamageableSystem.SetAllDamage(sDamageableEntity, sDamageableComponent, 0); Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); // Test 'wasted' healing sDamageableSystem.TryChangeDamage(uid, new DamageSpecifier(type3a, 5)); sDamageableSystem.TryChangeDamage(uid, new DamageSpecifier(type3b, 7)); sDamageableSystem.TryChangeDamage(uid, new DamageSpecifier(group3, -11)); Assert.Multiple(() => { Assert.That(sDamageableComponent.Damage.DamageDict[type3a.ID], Is.EqualTo(FixedPoint2.New(1.34))); Assert.That(sDamageableComponent.Damage.DamageDict[type3b.ID], Is.EqualTo(FixedPoint2.New(3.33))); Assert.That(sDamageableComponent.Damage.DamageDict[type3c.ID], Is.EqualTo(FixedPoint2.New(0))); }); // Test Over-Healing sDamageableSystem.TryChangeDamage(uid, new DamageSpecifier(group3, FixedPoint2.New(-100))); Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); // Test that if no health change occurred, returns false sDamageableSystem.TryChangeDamage(uid, new DamageSpecifier(group3, -100)); Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); }); await pair.CleanReturnAsync(); } } }