ECS damageable (#4529)

* ECS and damage Data

* Comments and newlines

* Added Comments

* Make TryChangeDamageEvent immutable

* Remove SetAllDamage event

Use public SetAllDamage function instead

* Undo destructible mistakes

That was some shit code.

* Rename DamageData to DamageSpecifier

And misc small edits

misc

* Cache trigger prototypes.

* Renaming destructible classes & functions

* Revert "Cache trigger prototypes."

This reverts commit 86bae15ba6616884dba75f552dfdfbe2d1fb6586.

* Replace prototypes with prototype IDs.

* Split damage.yml into individual files

* move get/handle component state to system

* Update HealthChange doc

* Make godmode call Dirty() on damageable component

* Add Initialize() to fix damage test

* Make non-static

* uncache resistance set prototype and trim DamageableComponentState

* Remove unnecessary Dirty() calls during initialization

* RemoveTryChangeDamageEvent

* revert Dirty()

* Fix MobState relying on DamageableComponent.Dirty()

* Fix DisposalUnit Tests.

These were previously failing, but because the async was not await-ed, this never raised the exception.

After I fixed MobState component, this exception stopped happening and instead the assertions started being tested & failing

* Disposal test 2: electric boogaloo

* Fix typos/mistakes

also add comments and fix spacing.

* Use Uids instead of IEntity

* fix merge

* Comments, a merge issue, and making some damage ignore resistances

* Extend DamageSpecifier and use it for DamageableComponent

* fix master merge

* Fix Disposal unit test. Again.

Snapgrids were removed in master

* Execute Exectute
This commit is contained in:
Leon Friedrich
2021-09-15 03:07:37 +10:00
committed by GitHub
parent 22cc42ff50
commit df584ad446
212 changed files with 2876 additions and 3441 deletions

View File

@@ -1,7 +1,7 @@
using System.Linq;
using System.Threading.Tasks;
using Content.Shared.Damage;
using Content.Shared.Damage.Components;
using Content.Shared.Damage.Prototypes;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
@@ -11,75 +11,76 @@ namespace Content.IntegrationTests.Tests.Damageable
{
[TestFixture]
[TestOf(typeof(DamageableComponent))]
[TestOf(typeof(DamageableSystem))]
public class DamageableTest : ContentIntegrationTest
{
private const string DamageableEntityId = "TestDamageableEntityId";
private const string Group1Id = "TestGroup1";
private const string Group2Id = "TestGroup2";
private const string Group3Id = "TestGroup3";
private string Prototypes = $@"
private const string Prototypes = @"
# Define some damage groups
- type: damageType
id: TestDamage11
id: TestDamage1
- type: damageType
id: TestDamage21
id: TestDamage2a
- type: damageType
id: TestDamage22
id: TestDamage2b
- type: damageType
id: TestDamage31
id: TestDamage3a
- type: damageType
id: TestDamage32
id: TestDamage3b
- type: damageType
id: TestDamage33
id: TestDamage3c
# Define damage Groups with 1,2,3 damage types
- type: damageGroup
id: {Group1Id}
id: TestGroup1
damageTypes:
- TestDamage11
- TestDamage1
- type: damageGroup
id: {Group2Id}
id: TestGroup2
damageTypes:
- TestDamage21
- TestDamage22
- TestDamage2a
- TestDamage2b
- type: damageGroup
id: {Group3Id}
id: TestGroup3
damageTypes:
- TestDamage31
- TestDamage32
- TestDamage33
- TestDamage3a
- TestDamage3b
- TestDamage3c
# we want to test a container that supports only full groups
# we will also give full support for group 2 IMPLICITLY by specifying all of its members are supported.
- type: resistanceSet
id: testResistances
# this space is intentionally left blank
# This container should not support TestDamage1 or TestDamage2b
- type: damageContainer
id: testSomeDamageContainer
id: testDamageContainer
defaultResistanceSet: testResistances
supportedGroups:
- {Group3Id}
- TestGroup3
supportedTypes:
- TestDamage21
- TestDamage22
- TestDamage2a
- type: entity
id: {DamageableEntityId}
name: {DamageableEntityId}
id: TestDamageableEntityId
name: TestDamageableEntityId
components:
- type: Damageable
damageContainer: testSomeDamageContainer
damageContainer: testDamageContainer
";
/// <summary>
/// Test a standard damageable components
/// </summary>
/// <remarks>
/// Only test scenarios where each damage type is a member of exactly one group, and all damageable components support whole groups, not lone damage types.
/// </remarks>
// public bool & function to determine whether dealing damage resulted in actual damage change
public bool DamageChanged = false;
public void DamageChangedListener(EntityUid _, DamageableComponent comp, DamageChangedEvent args)
{
DamageChanged = true;
}
[Test]
public async Task TestDamageableComponents()
{
@@ -93,360 +94,150 @@ namespace Content.IntegrationTests.Tests.Damageable
var sEntityManager = server.ResolveDependency<IEntityManager>();
var sMapManager = server.ResolveDependency<IMapManager>();
var sPrototypeManager = server.ResolveDependency<IPrototypeManager>();
var sEntitySystemManager = server.ResolveDependency<IEntitySystemManager>();
IEntity sDamageableEntity;
IDamageableComponent sDamageableComponent = null;
sEntityManager.EventBus.SubscribeLocalEvent<DamageableComponent, DamageChangedEvent>(DamageChangedListener);
IEntity sDamageableEntity = null;
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!;
int typeDamage, groupDamage;
await server.WaitPost(() =>
{
var mapId = sMapManager.NextMapId();
var coordinates = new MapCoordinates(0, 0, mapId);
sMapManager.CreateMap(mapId);
sDamageableEntity = sEntityManager.SpawnEntity(DamageableEntityId, coordinates);
sDamageableComponent = sDamageableEntity.GetComponent<IDamageableComponent>();
sDamageableEntity = sEntityManager.SpawnEntity("TestDamageableEntityId", coordinates);
sDamageableComponent = sDamageableEntity.GetComponent<DamageableComponent>();
sDamageableSystem = sEntitySystemManager.GetEntitySystem<DamageableSystem>();
group1 = sPrototypeManager.Index<DamageGroupPrototype>(Group1Id);
group2 = sPrototypeManager.Index<DamageGroupPrototype>(Group2Id);
group3 = sPrototypeManager.Index<DamageGroupPrototype>(Group3Id);
group1 = sPrototypeManager.Index<DamageGroupPrototype>("TestGroup1");
group2 = sPrototypeManager.Index<DamageGroupPrototype>("TestGroup2");
group3 = sPrototypeManager.Index<DamageGroupPrototype>("TestGroup3");
type1 = sPrototypeManager.Index<DamageTypePrototype>("TestDamage1");
type2a = sPrototypeManager.Index<DamageTypePrototype>("TestDamage2a");
type2b = sPrototypeManager.Index<DamageTypePrototype>("TestDamage2b");
type3a = sPrototypeManager.Index<DamageTypePrototype>("TestDamage3a");
type3b = sPrototypeManager.Index<DamageTypePrototype>("TestDamage3b");
type3c = sPrototypeManager.Index<DamageTypePrototype>("TestDamage3c");
});
await server.WaitRunTicks(5);
await server.WaitAssertion(() =>
{
// Check that the correct groups are supported by the container
Assert.That(sDamageableComponent.IsApplicableDamageGroup(group1), Is.False);
Assert.That(sDamageableComponent.IsApplicableDamageGroup(group2), Is.True);
Assert.That(sDamageableComponent.IsApplicableDamageGroup(group3), Is.True);
Assert.That(sDamageableComponent.IsFullySupportedDamageGroup(group1), Is.False);
Assert.That(sDamageableComponent.IsFullySupportedDamageGroup(group2), Is.True);
Assert.That(sDamageableComponent.IsFullySupportedDamageGroup(group3), Is.True);
var uid = sDamageableEntity.Uid;
// Check that the correct types are supported:
foreach (var group in sPrototypeManager.EnumeratePrototypes<DamageGroupPrototype>())
// Check that the correct types are supported.
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 = types.Count() * 5;
DamageSpecifier damage = new(group3, damageToDeal);
sDamageableSystem.TryChangeDamage(uid, damage, true);
Assert.That(DamageChanged);
DamageChanged = false;
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damageToDeal));
Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(damageToDeal));
foreach (var type in types)
{
foreach(var type in group.DamageTypes)
{
if (sDamageableComponent.IsFullySupportedDamageGroup(group))
{
Assert.That(sDamageableComponent.IsSupportedDamageType(type), Is.True);
}
else
{
Assert.That(sDamageableComponent.IsSupportedDamageType(type), Is.False);
}
}
Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type, out typeDamage));
Assert.That(typeDamage, Is.EqualTo(damageToDeal / types.Count()));
}
Assert.That(sDamageableComponent.IsFullySupportedDamageGroup(group1), Is.False);
Assert.That(sDamageableComponent.IsFullySupportedDamageGroup(group2), Is.True);
Assert.That(sDamageableComponent.IsFullySupportedDamageGroup(group3), Is.True);
// Check that damage works properly if perfectly divisible among group members
int damageToDeal, groupDamage, typeDamage; ;
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(0));
foreach (var damageGroup in sDamageableComponent.FullySupportedDamageGroups)
// Heal
sDamageableSystem.TryChangeDamage(uid, -damage);
Assert.That(DamageChanged);
DamageChanged = false;
Assert.That(sDamageableComponent.TotalDamage, Is.Zero);
Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(0));
foreach (var type in types)
{
var types = damageGroup.DamageTypes;
// Damage
damageToDeal = types.Count() * 5;
Assert.That(sDamageableComponent.TryChangeDamage(damageGroup, damageToDeal, true), Is.True);
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damageToDeal));
Assert.That(sDamageableComponent.TryGetDamage(damageGroup, out groupDamage), Is.True);
Assert.That(groupDamage, Is.EqualTo(damageToDeal));
foreach (var type in types)
{
Assert.That(sDamageableComponent.TryGetDamage(type, out typeDamage), Is.True);
Assert.That(typeDamage, Is.EqualTo(damageToDeal / types.Count()));
}
// Heal
Assert.That(sDamageableComponent.TryChangeDamage(damageGroup, -damageToDeal, true), Is.True);
Assert.That(sDamageableComponent.TotalDamage, Is.Zero);
Assert.That(sDamageableComponent.TryGetDamage(damageGroup, out groupDamage), Is.True);
Assert.That(groupDamage, Is.Zero);
foreach (var type in types)
{
Assert.That(sDamageableComponent.TryGetDamage(type, out typeDamage), Is.True);
Assert.That(typeDamage, Is.Zero);
}
Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type, out typeDamage));
Assert.That(typeDamage, Is.Zero);
}
// Check that damage works properly if it is NOT perfectly divisible among group members
foreach (var damageGroup in sDamageableComponent.FullySupportedDamageGroups)
types = group3.DamageTypes;
damageToDeal = types.Count() * 5 - 1;
damage = new DamageSpecifier(group3, damageToDeal);
sDamageableSystem.TryChangeDamage(uid, damage, true);
Assert.That(DamageChanged);
DamageChanged = false;
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damageToDeal));
Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(damageToDeal));
// integer rounding. In this case, first member gets 1 less than others.
Assert.That(sDamageableComponent.Damage.DamageDict[type3a.ID], Is.EqualTo(damageToDeal / types.Count()));
Assert.That(sDamageableComponent.Damage.DamageDict[type3b.ID], Is.EqualTo(1 + damageToDeal / types.Count()));
Assert.That(sDamageableComponent.Damage.DamageDict[type3c.ID], Is.EqualTo(1 + damageToDeal / types.Count()));
// Heal
sDamageableSystem.TryChangeDamage(uid, -damage);
Assert.That(DamageChanged);
DamageChanged = false;
Assert.That(sDamageableComponent.TotalDamage, Is.Zero);
Assert.That(sDamageableComponent.DamagePerGroup[group3.ID], Is.EqualTo(0));
foreach (var type in types)
{
var types = damageGroup.DamageTypes;
// Damage
damageToDeal = types.Count() * 5 - 1;
Assert.That(sDamageableComponent.TryChangeDamage(damageGroup, damageToDeal, true), Is.True);
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damageToDeal));
Assert.That(sDamageableComponent.TryGetDamage(damageGroup, out groupDamage), Is.True);
Assert.That(groupDamage, Is.EqualTo(damageToDeal));
foreach (var type in types)
{
Assert.That(sDamageableComponent.TryGetDamage(type, out typeDamage), Is.True);
float targetDamage = ((float) damageToDeal) / types.Count();
Assert.That(typeDamage, Is.InRange(targetDamage - 1, targetDamage + 1));
}
// Heal
Assert.That(sDamageableComponent.TryChangeDamage(damageGroup, -damageToDeal, true), Is.True);
Assert.That(sDamageableComponent.TotalDamage, Is.Zero);
Assert.That(sDamageableComponent.TryGetDamage(damageGroup, out groupDamage), Is.True);
Assert.That(groupDamage, Is.Zero);
foreach (var type in types)
{
Assert.That(sDamageableComponent.TryGetDamage(type, out typeDamage), Is.True);
Assert.That(typeDamage, Is.Zero);
}
Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type, out typeDamage));
Assert.That(typeDamage, Is.Zero);
}
// Test that unsupported groups return false when setting/getting damage (and don't change damage)
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(0));
foreach (var damageGroup in sPrototypeManager.EnumeratePrototypes<DamageGroupPrototype>())
{
if (sDamageableComponent.IsFullySupportedDamageGroup(damageGroup))
{
continue;
}
Assert.That(sDamageableComponent.IsApplicableDamageGroup(damageGroup), Is.False);
var types = damageGroup.DamageTypes;
damageToDeal = types.Count() * 5;
foreach (var type in types)
{
Assert.That(sDamageableComponent.IsSupportedDamageType(type), Is.False);
}
;
Assert.That(sDamageableComponent.TryChangeDamage(damageGroup, damageToDeal, true), Is.False);
Assert.That(sDamageableComponent.TryGetDamage(damageGroup, out groupDamage), Is.False);
foreach (var type in types)
{
Assert.That(sDamageableComponent.TryChangeDamage(type, damageToDeal, true), Is.False);
Assert.That(sDamageableComponent.TryGetDamage(type, out typeDamage), Is.False);
}
}
// Did damage change?
damage = new DamageSpecifier(group1, 10) + new DamageSpecifier(type2b, 10);
sDamageableSystem.TryChangeDamage(uid, damage, true);
Assert.That(DamageChanged, Is.False);
Assert.That(sDamageableComponent.DamagePerGroup.TryGetValue(group1.ID, out groupDamage), Is.False);
Assert.That(sDamageableComponent.Damage.DamageDict.TryGetValue(type1.ID, out typeDamage), Is.False);
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(0));
// Test total damage function
damageToDeal = 10;
Assert.True(sDamageableComponent.TryChangeDamage(group3, damageToDeal, true));
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damageToDeal));
var totalTypeDamage = 0;
foreach (var damageType in sDamageableComponent.SupportedDamageTypes)
{
Assert.True(sDamageableComponent.TryGetDamage(damageType, out typeDamage));
Assert.That(typeDamage, Is.LessThanOrEqualTo(damageToDeal));
totalTypeDamage += typeDamage;
}
Assert.That(totalTypeDamage, Is.EqualTo(damageToDeal));
// Test healing all damage
Assert.That(sDamageableComponent.TrySetAllDamage(0));
// Test SetAll function
sDamageableSystem.SetAllDamage(sDamageableComponent, 10);
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(10 * sDamageableComponent.Damage.DamageDict.Count()));
sDamageableSystem.SetAllDamage(sDamageableComponent, 0);
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(0));
// Test preferential healing
damageToDeal = 12;
var damageTypes = group3.DamageTypes.ToArray();
// 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.That(sDamageableComponent.Damage.DamageDict[type3a.ID], Is.EqualTo(2));
Assert.That(sDamageableComponent.Damage.DamageDict[type3b.ID], Is.EqualTo(3));
Assert.That(sDamageableComponent.Damage.DamageDict[type3c.ID], Is.EqualTo(0));
// Deal damage
Assert.True(sDamageableComponent.TryChangeDamage(damageTypes[0], 17));
Assert.True(sDamageableComponent.TryChangeDamage(damageTypes[1], 31));
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(48));
// Heal group damage
Assert.True(sDamageableComponent.TryChangeDamage(group3, -11));
// Check healing (3 + 9)
Assert.That(sDamageableComponent.GetDamage(damageTypes[0]), Is.EqualTo(14));
Assert.That(sDamageableComponent.GetDamage(damageTypes[1]), Is.EqualTo(23));
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(37));
// Heal group damage
Assert.True(sDamageableComponent.TryChangeDamage(group3, -36));
// Check healing (13 + 23)
Assert.That(sDamageableComponent.GetDamage(damageTypes[0]), Is.EqualTo(1));
Assert.That(sDamageableComponent.GetDamage(damageTypes[1]), Is.EqualTo(0));
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(1));
//Check Damage
Assert.True(sDamageableComponent.TryGetDamage(damageTypes[0], out typeDamage));
Assert.That(typeDamage, Is.LessThanOrEqualTo(damageToDeal));
});
}
private const string SharedDamageTypeId = "TestSharedDamage";
private const string UnsupportedDamageTypeId = "TestUnsupportedDamage";
private string Prototypes2 = $@"
- type: damageType
id: {SharedDamageTypeId}
- type: damageType
id: {UnsupportedDamageTypeId}
- type: damageType
id: TestDamage1
- type: damageType
id: TestDamage2
- type: damageGroup
id: {Group1Id}
damageTypes:
- {SharedDamageTypeId}
- type: damageGroup
id: {Group2Id}
damageTypes:
- {SharedDamageTypeId}
- TestDamage1
- type: damageGroup
id: {Group3Id}
damageTypes:
- {SharedDamageTypeId}
- TestDamage2
- {UnsupportedDamageTypeId}
# we want to test a container that only partially supports a group:
- type: damageContainer
id: TestPartiallySupported
supportedGroups:
- {Group2Id}
supportedTypes:
- TestDamage2
- TestDamage1
# does NOT support type {UnsupportedDamageTypeId}, and thus does not fully support group {Group3Id}
# TestDamage1 is added twice because it is also in {Group2Id}. This should not cause errors.
# create entities
- type: entity
id: {DamageableEntityId}
name: {DamageableEntityId}
components:
- type: Damageable
damageContainer: TestPartiallySupported
";
/// <summary>
/// Generalized damageable component tests.
/// </summary>
/// <remarks>
/// Test scenarios where damage types are members of more than one group, or where a component only supports a subset of a group.
/// </remarks>
[Test]
public async Task TestGeneralizedDamageableComponent()
{
var server = StartServerDummyTicker(new ServerContentIntegrationOption
{
ExtraPrototypes = Prototypes2
});
await server.WaitIdleAsync();
var sEntityManager = server.ResolveDependency<IEntityManager>();
var sMapManager = server.ResolveDependency<IMapManager>();
var sPrototypeManager = server.ResolveDependency<IPrototypeManager>();
IEntity sDamageableEntity;
IDamageableComponent sDamageableComponent = null;
DamageGroupPrototype group1 = default!;
DamageGroupPrototype group2 = default!;
DamageGroupPrototype group3 = default!;
DamageTypePrototype SharedDamageType = default!;
DamageTypePrototype UnsupportedDamageType = default!;
await server.WaitPost(() =>
{
var mapId = sMapManager.NextMapId();
var coordinates = new MapCoordinates(0, 0, mapId);
sMapManager.CreateMap(mapId);
sDamageableEntity = sEntityManager.SpawnEntity(DamageableEntityId, coordinates);
sDamageableComponent = sDamageableEntity.GetComponent<IDamageableComponent>();
group1 = sPrototypeManager.Index<DamageGroupPrototype>(Group1Id);
group2 = sPrototypeManager.Index<DamageGroupPrototype>(Group2Id);
group3 = sPrototypeManager.Index<DamageGroupPrototype>(Group3Id);
SharedDamageType = sPrototypeManager.Index<DamageTypePrototype>(SharedDamageTypeId);
UnsupportedDamageType = sPrototypeManager.Index<DamageTypePrototype>(UnsupportedDamageTypeId);
});
await server.WaitRunTicks(5);
await server.WaitAssertion(() =>
{
// All damage types should be applicable
Assert.That(sDamageableComponent.IsApplicableDamageGroup(group1), Is.True);
Assert.That(sDamageableComponent.IsApplicableDamageGroup(group2), Is.True);
Assert.That(sDamageableComponent.IsApplicableDamageGroup(group3), Is.True);
// But not all should be fully supported
Assert.That(sDamageableComponent.IsFullySupportedDamageGroup(group1), Is.True);
Assert.That(sDamageableComponent.IsFullySupportedDamageGroup(group2), Is.True);
Assert.That(sDamageableComponent.IsFullySupportedDamageGroup(group3), Is.False);
// Check that the correct damage types are supported
Assert.That(sDamageableComponent.IsSupportedDamageType(SharedDamageType), Is.True);
// Check that if we deal damage using a type appearing in multiple groups, nothing goes wrong.
var damage = 12;
Assert.That(sDamageableComponent.TryChangeDamage(SharedDamageType, damage), Is.True);
Assert.That(sDamageableComponent.GetDamage(SharedDamageType), Is.EqualTo(damage));
Assert.That(sDamageableComponent.GetDamage(group1), Is.EqualTo(damage));
Assert.That(sDamageableComponent.GetDamage(group2), Is.EqualTo(damage));
Assert.That(sDamageableComponent.GetDamage(group3), Is.EqualTo(damage));
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damage));
// Check that if we deal damage using a group that is not fully supported, the damage is reduced
// Note that if damage2 were not neatly divisible by 3, the actual damage reduction would be subject to integer rounding.
// How much exactly the damage gets reduced then would depend on the order that the groups were defined in the yaml file
// Here we deal 9 damage. It should apply 3 damage to each type, but one type is ignored, resulting in 6 total damage.
// However, the damage in group2 and group3 only changes because of one type that overlaps, so they only change by 3
Assert.That(sDamageableComponent.TryChangeDamage(group3, 9), Is.True);
Assert.That(sDamageableComponent.GetDamage(group1), Is.EqualTo(damage + 3));
Assert.That(sDamageableComponent.GetDamage(group2), Is.EqualTo(damage + 3));
Assert.That(sDamageableComponent.GetDamage(group3), Is.EqualTo(damage + 6));
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damage + 6));
// Now we check that when healing, no damage is wasted.
// Because SharedDamageType has the most damage in group3 (15 vs 3), it will be healed more than the other.
// Expect that, up to integer rounding, one is healed 5* more than the other.
// We will use a number that does not divide nicely, there will be some integer rounding.
Assert.That(sDamageableComponent.TryChangeDamage(group3, -7), Is.True);
Assert.That(sDamageableComponent.GetDamage(group1), Is.EqualTo(damage + 3 - 5));
Assert.That(sDamageableComponent.GetDamage(group2), Is.EqualTo(damage + 3 - 5));
Assert.That(sDamageableComponent.GetDamage(group3), Is.EqualTo(damage + 6 - 7));
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(damage + 6 - 7));
// Test Over-Healing
sDamageableSystem.TryChangeDamage(uid, new DamageSpecifier(group3, -100));
Assert.That(DamageChanged);
DamageChanged = false;
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(0));
// Test that if no health change occurred, returns false
sDamageableSystem.TryChangeDamage(uid, new DamageSpecifier(group3, -100));
Assert.That(DamageChanged, Is.False);
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(0));
});
}
}