Beispiel #1
0
        public async Task Test()
        {
            var server = StartServer(new ServerContentIntegrationOption
            {
                ExtraPrototypes = Prototypes
            });

            await server.WaitIdleAsync();

            var sEntityManager       = server.ResolveDependency <IEntityManager>();
            var sMapManager          = server.ResolveDependency <IMapManager>();
            var sPrototypeManager    = server.ResolveDependency <IPrototypeManager>();
            var sEntitySystemManager = server.ResolveDependency <IEntitySystemManager>();

            EntityUid sDestructibleEntity = default;
            TestDestructibleListenerSystem sTestThresholdListenerSystem = null;

            await server.WaitPost(() =>
            {
                var gridId      = GetMainGrid(sMapManager).GridEntityId;
                var coordinates = new EntityCoordinates(gridId, 0, 0);

                sDestructibleEntity          = sEntityManager.SpawnEntity(DestructibleDestructionEntityId, coordinates);
                sTestThresholdListenerSystem = sEntitySystemManager.GetEntitySystem <TestDestructibleListenerSystem>();
            });

            await server.WaitAssertion(() =>
            {
                var coordinates             = IoCManager.Resolve <IEntityManager>().GetComponent <TransformComponent>(sDestructibleEntity).Coordinates;
                var bruteDamageGroup        = sPrototypeManager.Index <DamageGroupPrototype>("TestBrute");
                DamageSpecifier bruteDamage = new(bruteDamageGroup, 50);

                Assert.DoesNotThrow(() =>
                {
                    EntitySystem.Get <DamageableSystem>().TryChangeDamage(sDestructibleEntity, bruteDamage, true);
                });

                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                var threshold = sTestThresholdListenerSystem.ThresholdsReached[0].Threshold;

                Assert.That(threshold.Triggered, Is.True);
                Assert.That(threshold.Behaviors.Count, Is.EqualTo(3));

                var spawnEntitiesBehavior = (SpawnEntitiesBehavior)threshold.Behaviors.Single(b => b is SpawnEntitiesBehavior);

                Assert.That(spawnEntitiesBehavior.Spawn.Count, Is.EqualTo(1));
                Assert.That(spawnEntitiesBehavior.Spawn.Keys.Single(), Is.EqualTo(SpawnedEntityId));
                Assert.That(spawnEntitiesBehavior.Spawn.Values.Single(), Is.EqualTo(new MinMax {
                    Min = 1, Max = 1
                }));

                var entitiesInRange = IoCManager.Resolve <IEntityLookup>().GetEntitiesInRange(coordinates, 2);
                var found           = false;

                foreach (var entity in entitiesInRange)
                {
                    if (sEntityManager.GetComponent <MetaDataComponent>(entity).EntityPrototype == null)
                    {
                        continue;
                    }

                    if (sEntityManager.GetComponent <MetaDataComponent>(entity).EntityPrototype?.Name != SpawnedEntityId)
                    {
                        continue;
                    }

                    found = true;
                    break;
                }

                Assert.That(found, Is.True);
            });
        }
Beispiel #2
0
        public async Task Test()
        {
            await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings { NoClient = true, ExtraPrototypes = Prototypes });

            var server = pairTracker.Pair.Server;

            var testMap = await PoolManager.CreateTestMap(pairTracker);

            var sEntityManager       = server.ResolveDependency <IEntityManager>();
            var sPrototypeManager    = server.ResolveDependency <IPrototypeManager>();
            var sEntitySystemManager = server.ResolveDependency <IEntitySystemManager>();

            EntityUid sDestructibleEntity = default;
            TestDestructibleListenerSystem sTestThresholdListenerSystem = null;

            await server.WaitPost(() =>
            {
                var coordinates = testMap.GridCoords;

                sDestructibleEntity          = sEntityManager.SpawnEntity(DestructibleDestructionEntityId, coordinates);
                sTestThresholdListenerSystem = sEntitySystemManager.GetEntitySystem <TestDestructibleListenerSystem>();
            });

            await server.WaitAssertion(() =>
            {
                var coordinates             = IoCManager.Resolve <IEntityManager>().GetComponent <TransformComponent>(sDestructibleEntity).Coordinates;
                var bruteDamageGroup        = sPrototypeManager.Index <DamageGroupPrototype>("TestBrute");
                DamageSpecifier bruteDamage = new(bruteDamageGroup, 50);

                Assert.DoesNotThrow(() =>
                {
                    EntitySystem.Get <DamageableSystem>().TryChangeDamage(sDestructibleEntity, bruteDamage, true);
                });

                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                var threshold = sTestThresholdListenerSystem.ThresholdsReached[0].Threshold;

                Assert.That(threshold.Triggered, Is.True);
                Assert.That(threshold.Behaviors.Count, Is.EqualTo(3));

                var spawnEntitiesBehavior = (SpawnEntitiesBehavior)threshold.Behaviors.Single(b => b is SpawnEntitiesBehavior);

                Assert.That(spawnEntitiesBehavior.Spawn.Count, Is.EqualTo(1));
                Assert.That(spawnEntitiesBehavior.Spawn.Keys.Single(), Is.EqualTo(SpawnedEntityId));
                Assert.That(spawnEntitiesBehavior.Spawn.Values.Single(), Is.EqualTo(new MinMax {
                    Min = 1, Max = 1
                }));

                var entitiesInRange = EntitySystem.Get <EntityLookupSystem>().GetEntitiesInRange(coordinates, 2);
                var found           = false;

                foreach (var entity in entitiesInRange)
                {
                    if (sEntityManager.GetComponent <MetaDataComponent>(entity).EntityPrototype == null)
                    {
                        continue;
                    }

                    if (sEntityManager.GetComponent <MetaDataComponent>(entity).EntityPrototype?.Name != SpawnedEntityId)
                    {
                        continue;
                    }

                    found = true;
                    break;
                }

                Assert.That(found, Is.True);
            });

            await pairTracker.CleanReturnAsync();
        }
Beispiel #3
0
        public async Task AndTest()
        {
            var server = StartServer(new ServerContentIntegrationOption
            {
                ExtraPrototypes = Prototypes
            });

            await server.WaitIdleAsync();

            var sEntityManager = server.ResolveDependency<IEntityManager>();
            var sMapManager = server.ResolveDependency<IMapManager>();
            var sPrototypeManager = server.ResolveDependency<IPrototypeManager>();
            var sEntitySystemManager = server.ResolveDependency<IEntitySystemManager>();

            EntityUid sDestructibleEntity = default;
            DamageableComponent sDamageableComponent = null;
            TestDestructibleListenerSystem sTestThresholdListenerSystem = null;
            DamageableSystem sDamageableSystem = null;

            await server.WaitPost(() =>
            {
                var gridId = GetMainGrid(sMapManager).GridEntityId;
                var coordinates = new EntityCoordinates(gridId, 0, 0);

                sDestructibleEntity = sEntityManager.SpawnEntity(DestructibleDamageGroupEntityId, coordinates);
                sDamageableComponent = IoCManager.Resolve<IEntityManager>().GetComponent<DamageableComponent>(sDestructibleEntity);

                sTestThresholdListenerSystem = sEntitySystemManager.GetEntitySystem<TestDestructibleListenerSystem>();
                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                sDamageableSystem = sEntitySystemManager.GetEntitySystem<DamageableSystem>();
            });

            await server.WaitRunTicks(5);

            await server.WaitAssertion(() =>
            {
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);
            });

            await server.WaitAssertion(() =>
            {
                var bruteDamageGroup = sPrototypeManager.Index<DamageGroupPrototype>("TestBrute");
                var burnDamageGroup = sPrototypeManager.Index<DamageGroupPrototype>("TestBurn");

                DamageSpecifier bruteDamage = new(bruteDamageGroup, FixedPoint2.New(5));
                DamageSpecifier burnDamage = new(burnDamageGroup, FixedPoint2.New(5));

                // Raise brute damage to 5
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bruteDamage, true);

                // No thresholds reached yet, the earliest one is at 10 damage
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise brute damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bruteDamage, true);

                // No threshold reached, burn needs to be 10 as well
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise burn damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, burnDamage * 2, true);

                // One threshold reached, brute 10 + burn 10
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                // Threshold brute 10 + burn 10
                var msg = sTestThresholdListenerSystem.ThresholdsReached[0];
                var threshold = msg.Threshold;

                // Check that it matches the YAML prototype
                Assert.That(threshold.Behaviors, Is.Empty);
                Assert.NotNull(threshold.Trigger);
                Assert.That(threshold.Triggered, Is.True);
                Assert.IsInstanceOf<AndTrigger>(threshold.Trigger);

                var trigger = (AndTrigger) threshold.Trigger;

                Assert.IsInstanceOf<DamageGroupTrigger>(trigger.Triggers[0]);
                Assert.IsInstanceOf<DamageGroupTrigger>(trigger.Triggers[1]);

                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                // Raise brute damage to 20
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bruteDamage * 2, true);

                // No new thresholds reached
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise burn damage to 20
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, burnDamage * 2, true);

                // No new thresholds reached
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Lower brute damage to 0
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bruteDamage * -10);
                Assert.That(sDamageableComponent.TotalDamage,Is.EqualTo(FixedPoint2.New(20)));

                // No new thresholds reached, healing should not trigger it
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise brute damage back up to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bruteDamage * 2, true);

                // 10 brute + 10 burn threshold reached, brute was healed and brought back to its threshold amount and slash stayed the same
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                // Heal both classes of damage to 0
                sDamageableSystem.SetAllDamage(sDamageableComponent, 0);

                // No new thresholds reached, healing should not trigger it
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise brute damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bruteDamage * 2, true);

                // No new thresholds reached
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise burn damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, burnDamage * 2, true);

                // Both classes of damage were healed and then raised again, the threshold should have been reached as triggers once is default false
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                // Threshold brute 10 + burn 10
                msg = sTestThresholdListenerSystem.ThresholdsReached[0];
                threshold = msg.Threshold;

                // Check that it matches the YAML prototype
                Assert.That(threshold.Behaviors, Is.Empty);
                Assert.NotNull(threshold.Trigger);
                Assert.That(threshold.Triggered, Is.True);
                Assert.IsInstanceOf<AndTrigger>(threshold.Trigger);

                trigger = (AndTrigger) threshold.Trigger;

                Assert.IsInstanceOf<DamageGroupTrigger>(trigger.Triggers[0]);
                Assert.IsInstanceOf<DamageGroupTrigger>(trigger.Triggers[1]);

                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                // Change triggers once to true
                threshold.TriggersOnce = true;

                // Heal brute and burn back to 0
                sDamageableSystem.SetAllDamage(sDamageableComponent, 0);

                // No new thresholds reached from healing
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise brute damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bruteDamage * 2, true);

                // No new thresholds reached
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise burn damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, burnDamage * 2, true);

                // No new thresholds reached as triggers once is set to true and it already triggered before
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);
            });
        }
        public async Task Test()
        {
            await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings { NoClient = true, ExtraPrototypes = Prototypes });

            var server = pairTracker.Pair.Server;

            var testMap = await PoolManager.CreateTestMap(pairTracker);

            var sEntityManager       = server.ResolveDependency <IEntityManager>();
            var sEntitySystemManager = server.ResolveDependency <IEntitySystemManager>();

            EntityUid                      sDestructibleEntity          = default;
            DamageableComponent            sDamageableComponent         = null;
            TestDestructibleListenerSystem sTestThresholdListenerSystem = null;
            DamageableSystem               sDamageableSystem            = null;

            await server.WaitPost(() =>
            {
                var coordinates = testMap.GridCoords;

                sDestructibleEntity          = sEntityManager.SpawnEntity(DestructibleDamageTypeEntityId, coordinates);
                sDamageableComponent         = IoCManager.Resolve <IEntityManager>().GetComponent <DamageableComponent>(sDestructibleEntity);
                sTestThresholdListenerSystem = sEntitySystemManager.GetEntitySystem <TestDestructibleListenerSystem>();
                sTestThresholdListenerSystem.ThresholdsReached.Clear();
                sDamageableSystem = sEntitySystemManager.GetEntitySystem <DamageableSystem>();
            });

            await server.WaitRunTicks(5);

            await server.WaitAssertion(() =>
            {
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);
            });

            await server.WaitAssertion(() =>
            {
                var bluntDamageType = IoCManager.Resolve <IPrototypeManager>().Index <DamageTypePrototype>("TestBlunt");
                var slashDamageType = IoCManager.Resolve <IPrototypeManager>().Index <DamageTypePrototype>("TestSlash");

                var bluntDamage = new DamageSpecifier(bluntDamageType, 5);
                var slashDamage = new DamageSpecifier(slashDamageType, 5);

                // Raise blunt damage to 5
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage, true);

                // No thresholds reached yet, the earliest one is at 10 damage
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise blunt damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage, true);

                // No threshold reached, slash needs to be 10 as well
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise slash damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, slashDamage * 2, true);

                // One threshold reached, blunt 10 + slash 10
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                // Threshold blunt 10 + slash 10
                var msg       = sTestThresholdListenerSystem.ThresholdsReached[0];
                var threshold = msg.Threshold;

                // Check that it matches the YAML prototype
                Assert.That(threshold.Behaviors, Is.Empty);
                Assert.NotNull(threshold.Trigger);
                Assert.That(threshold.Triggered, Is.True);
                Assert.IsInstanceOf <AndTrigger>(threshold.Trigger);

                var trigger = (AndTrigger)threshold.Trigger;

                Assert.IsInstanceOf <DamageTypeTrigger>(trigger.Triggers[0]);
                Assert.IsInstanceOf <DamageTypeTrigger>(trigger.Triggers[1]);

                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                // Raise blunt damage to 20
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 2, true);

                // No new thresholds reached
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise slash damage to 20
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, slashDamage * 2, true);

                // No new thresholds reached
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Lower blunt damage to 0
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * -4, true);

                // No new thresholds reached, healing should not trigger it
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise blunt damage back up to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 2, true);

                // 10 blunt + 10 slash threshold reached, blunt was healed and brought back to its threshold amount and slash stayed the same
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                // Heal both types of damage to 0
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * -2, true);
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, slashDamage * -4, true);

                // No new thresholds reached, healing should not trigger it
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise blunt damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 2, true);

                // No new thresholds reached
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise slash damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, slashDamage * 2, true);

                // Both types of damage were healed and then raised again, the threshold should have been reached as triggers once is default false
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                // Threshold blunt 10 + slash 10
                msg       = sTestThresholdListenerSystem.ThresholdsReached[0];
                threshold = msg.Threshold;

                // Check that it matches the YAML prototype
                Assert.That(threshold.Behaviors, Is.Empty);
                Assert.NotNull(threshold.Trigger);
                Assert.That(threshold.Triggered, Is.True);
                Assert.IsInstanceOf <AndTrigger>(threshold.Trigger);

                trigger = (AndTrigger)threshold.Trigger;

                Assert.IsInstanceOf <DamageTypeTrigger>(trigger.Triggers[0]);
                Assert.IsInstanceOf <DamageTypeTrigger>(trigger.Triggers[1]);

                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                // Change triggers once to true
                threshold.TriggersOnce = true;

                // Heal blunt and slash back to 0
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * -2, true);
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, slashDamage * -2, true);

                // No new thresholds reached from healing
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise blunt damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 2, true);

                // No new thresholds reached
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Raise slash damage to 10
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, slashDamage * 2, true);

                // No new thresholds reached as triggers once is set to true and it already triggered before
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);
            });

            await pairTracker.CleanReturnAsync();
        }
Beispiel #5
0
        public async Task Test()
        {
            var server = StartServer(new ServerContentIntegrationOption
            {
                ExtraPrototypes = Prototypes
            });

            await server.WaitIdleAsync();

            var sEntityManager       = server.ResolveDependency <IEntityManager>();
            var sMapManager          = server.ResolveDependency <IMapManager>();
            var sPrototypeManager    = server.ResolveDependency <IPrototypeManager>();
            var sEntitySystemManager = server.ResolveDependency <IEntitySystemManager>();

            EntityUid                      sDestructibleEntity          = default;
            DamageableComponent            sDamageableComponent         = null;
            DestructibleComponent          sDestructibleComponent       = null;
            TestDestructibleListenerSystem sTestThresholdListenerSystem = null;
            DamageableSystem               sDamageableSystem            = null;

            await server.WaitPost(() =>
            {
                var gridId      = GetMainGrid(sMapManager).GridEntityId;
                var coordinates = new EntityCoordinates(gridId, 0, 0);

                sDestructibleEntity    = sEntityManager.SpawnEntity(DestructibleEntityId, coordinates);
                sDamageableComponent   = IoCManager.Resolve <IEntityManager>().GetComponent <DamageableComponent>(sDestructibleEntity);
                sDestructibleComponent = IoCManager.Resolve <IEntityManager>().GetComponent <DestructibleComponent>(sDestructibleEntity);

                sTestThresholdListenerSystem = sEntitySystemManager.GetEntitySystem <TestDestructibleListenerSystem>();
                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                sDamageableSystem = sEntitySystemManager.GetEntitySystem <DamageableSystem>();
            });

            await server.WaitRunTicks(5);

            await server.WaitAssertion(() =>
            {
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);
            });

            await server.WaitAssertion(() =>
            {
                var bluntDamage = new DamageSpecifier(sPrototypeManager.Index <DamageTypePrototype>("TestBlunt"), 10);

                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage, true);

                // No thresholds reached yet, the earliest one is at 20 damage
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage, true);

                // Only one threshold reached, 20
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                // Threshold 20
                var msg       = sTestThresholdListenerSystem.ThresholdsReached[0];
                var threshold = msg.Threshold;

                // Check that it matches the YAML prototype
                Assert.That(threshold.Behaviors, Is.Empty);
                Assert.NotNull(threshold.Trigger);
                Assert.That(threshold.Triggered, Is.True);

                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 3, true);

                // One threshold reached, 50, since 20 already triggered before and it has not been healed below that amount
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                // Threshold 50
                msg       = sTestThresholdListenerSystem.ThresholdsReached[0];
                threshold = msg.Threshold;

                // Check that it matches the YAML prototype
                Assert.That(threshold.Behaviors, Has.Count.EqualTo(3));

                var soundThreshold = (PlaySoundBehavior)threshold.Behaviors[0];
                var spawnThreshold = (SpawnEntitiesBehavior)threshold.Behaviors[1];
                var actsThreshold  = (DoActsBehavior)threshold.Behaviors[2];

                Assert.That(actsThreshold.Acts, Is.EqualTo(ThresholdActs.Breakage));
                Assert.That(soundThreshold.Sound.GetSound(), Is.EqualTo("/Audio/Effects/woodhit.ogg"));
                Assert.That(spawnThreshold.Spawn, Is.Not.Null);
                Assert.That(spawnThreshold.Spawn.Count, Is.EqualTo(1));
                Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo(SpawnedEntityId));
                Assert.That(spawnThreshold.Spawn.Single().Value.Min, Is.EqualTo(1));
                Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1));
                Assert.NotNull(threshold.Trigger);
                Assert.That(threshold.Triggered, Is.True);

                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                // Damage for 50 again, up to 100 now
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 5, true);

                // No thresholds reached as they weren't healed below the trigger amount
                Assert.IsEmpty(sTestThresholdListenerSystem.ThresholdsReached);

                // Set damage to 0
                sDamageableSystem.SetAllDamage(sDamageableComponent, 0);

                // Damage for 100, up to 100
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 10, true);

                // Two thresholds reached as damage increased past the previous, 20 and 50
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(2));

                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                // Heal the entity for 40 damage, down to 60
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * -4, true);

                // Thresholds don't work backwards
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty);

                // Damage for 10, up to 70
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage, true);

                // Not enough healing to de-trigger a threshold
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty);

                // Heal by 30, down to 40
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * -3, true);

                // Thresholds don't work backwards
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty);

                // Damage up to 50 again
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage, true);

                // The 50 threshold should have triggered again, after being healed
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached.Count, Is.EqualTo(1));

                msg       = sTestThresholdListenerSystem.ThresholdsReached[0];
                threshold = msg.Threshold;

                // Check that it matches the YAML prototype
                Assert.That(threshold.Behaviors, Has.Count.EqualTo(3));

                soundThreshold = (PlaySoundBehavior)threshold.Behaviors[0];
                spawnThreshold = (SpawnEntitiesBehavior)threshold.Behaviors[1];
                actsThreshold  = (DoActsBehavior)threshold.Behaviors[2];

                // Check that it matches the YAML prototype
                Assert.That(actsThreshold.Acts, Is.EqualTo(ThresholdActs.Breakage));
                Assert.That(soundThreshold.Sound.GetSound(), Is.EqualTo("/Audio/Effects/woodhit.ogg"));
                Assert.That(spawnThreshold.Spawn, Is.Not.Null);
                Assert.That(spawnThreshold.Spawn.Count, Is.EqualTo(1));
                Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo(SpawnedEntityId));
                Assert.That(spawnThreshold.Spawn.Single().Value.Min, Is.EqualTo(1));
                Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1));
                Assert.NotNull(threshold.Trigger);
                Assert.That(threshold.Triggered, Is.True);

                // Reset thresholds reached
                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                // Heal all damage
                sDamageableSystem.SetAllDamage(sDamageableComponent, 0);

                // Damage up to 50
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 5, true);

                // Check that the total damage matches
                Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(50)));

                // Both thresholds should have triggered
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Has.Exactly(2).Items);

                // Verify the first one, should be the lowest one (20)
                msg         = sTestThresholdListenerSystem.ThresholdsReached[0];
                var trigger = (DamageTrigger)msg.Threshold.Trigger;
                Assert.NotNull(trigger);
                Assert.That(trigger.Damage, Is.EqualTo(20));

                threshold = msg.Threshold;

                // Check that it matches the YAML prototype
                Assert.That(threshold.Behaviors, Is.Empty);

                // Verify the second one, should be the highest one (50)
                msg     = sTestThresholdListenerSystem.ThresholdsReached[1];
                trigger = (DamageTrigger)msg.Threshold.Trigger;
                Assert.NotNull(trigger);
                Assert.That(trigger.Damage, Is.EqualTo(50));

                threshold = msg.Threshold;

                Assert.That(threshold.Behaviors, Has.Count.EqualTo(3));

                soundThreshold = (PlaySoundBehavior)threshold.Behaviors[0];
                spawnThreshold = (SpawnEntitiesBehavior)threshold.Behaviors[1];
                actsThreshold  = (DoActsBehavior)threshold.Behaviors[2];

                // Check that it matches the YAML prototype
                Assert.That(actsThreshold.Acts, Is.EqualTo(ThresholdActs.Breakage));
                Assert.That(soundThreshold.Sound.GetSound(), Is.EqualTo("/Audio/Effects/woodhit.ogg"));
                Assert.That(spawnThreshold.Spawn, Is.Not.Null);
                Assert.That(spawnThreshold.Spawn.Count, Is.EqualTo(1));
                Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo(SpawnedEntityId));
                Assert.That(spawnThreshold.Spawn.Single().Value.Min, Is.EqualTo(1));
                Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1));
                Assert.NotNull(threshold.Trigger);
                Assert.That(threshold.Triggered, Is.True);

                // Reset thresholds reached
                sTestThresholdListenerSystem.ThresholdsReached.Clear();

                // Heal the entity completely
                sDamageableSystem.SetAllDamage(sDamageableComponent, 0);

                // Check that the entity has 0 damage
                Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.Zero));

                // Set both thresholds to only trigger once
                foreach (var destructibleThreshold in sDestructibleComponent.Thresholds)
                {
                    Assert.NotNull(destructibleThreshold.Trigger);
                    destructibleThreshold.TriggersOnce = true;
                }

                // Damage the entity up to 50 damage again
                sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage * 5, true);

                // Check that the total damage matches
                Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(50)));

                // No thresholds should have triggered as they were already triggered before, and they are set to only trigger once
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty);

                // Set both thresholds to trigger multiple times
                foreach (var destructibleThreshold in sDestructibleComponent.Thresholds)
                {
                    Assert.NotNull(destructibleThreshold.Trigger);
                    destructibleThreshold.TriggersOnce = false;
                }

                // Check that the total damage matches
                Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(FixedPoint2.New(50)));

                // They shouldn't have been triggered by changing TriggersOnce
                Assert.That(sTestThresholdListenerSystem.ThresholdsReached, Is.Empty);
            });
        }