Add destructible component threshold triggers (#3080)

* WIP changes

* Fix tests, merge conflict and trigger once behavior

* Update yml

* Change test strings to be consts

* Fix total damage types and classes triggers

* Simplify damage trigger logic, move state to Threshold

* Update outdated code and docs

* Change the name of IBehavior back to IThresholdBehavior

* Change human gibbing to trigger at 400 brute damage

* Change gibbing from brute to blunt damage

* Fix one (1) typo

* Add damage class trigger test

* Add missing nullable enable to thresholds
This commit is contained in:
DrSmugleaf
2021-02-05 13:41:05 +01:00
committed by GitHub
parent 9640c33210
commit b62cc84e8c
71 changed files with 1678 additions and 899 deletions

View File

@@ -0,0 +1,170 @@
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Destructible.Thresholds.Triggers;
using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage;
using NUnit.Framework;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using static Content.IntegrationTests.Tests.Destructible.DestructibleTestPrototypes;
namespace Content.IntegrationTests.Tests.Destructible
{
[TestFixture]
[TestOf(typeof(TotalDamageClassesTrigger))]
public class DestructibleDamageClassTest : ContentIntegrationTest
{
[Test]
public async Task Test()
{
var server = StartServerDummyTicker(new ServerContentIntegrationOption
{
ExtraPrototypes = Prototypes,
ContentBeforeIoC = () =>
{
IoCManager.Resolve<IComponentFactory>().Register<TestThresholdListenerComponent>();
}
});
await server.WaitIdleAsync();
var sEntityManager = server.ResolveDependency<IEntityManager>();
var sMapManager = server.ResolveDependency<IMapManager>();
IEntity sDestructibleEntity;
IDamageableComponent sDamageableComponent = null;
TestThresholdListenerComponent sThresholdListenerComponent = null;
await server.WaitPost(() =>
{
var mapId = new MapId(1);
var coordinates = new MapCoordinates(0, 0, mapId);
sMapManager.CreateMap(mapId);
sDestructibleEntity = sEntityManager.SpawnEntity(DestructibleDamageClassEntityId, coordinates);
sDamageableComponent = sDestructibleEntity.GetComponent<IDamageableComponent>();
sThresholdListenerComponent = sDestructibleEntity.GetComponent<TestThresholdListenerComponent>();
});
await server.WaitRunTicks(5);
await server.WaitAssertion(() =>
{
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
});
await server.WaitAssertion(() =>
{
// Raise brute damage to 5
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, 5, true));
// No thresholds reached yet, the earliest one is at 10 damage
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise brute damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, 5, true));
// No threshold reached, burn needs to be 10 as well
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise burn damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Burn, 10, true));
// One threshold reached, brute 10 + burn 10
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
// Threshold brute 10 + burn 10
var msg = sThresholdListenerComponent.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<TotalDamageClassesTrigger>(threshold.Trigger);
sThresholdListenerComponent.ThresholdsReached.Clear();
// Raise brute damage to 20
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, 10, true));
// No new thresholds reached
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise burn damage to 20
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Burn, 10, true));
// No new thresholds reached
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Lower brute damage to 0
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, -20, true));
// No new thresholds reached, healing should not trigger it
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise brute damage back up to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, 10, true));
// 10 brute + 10 burn threshold reached, brute was healed and brought back to its threshold amount and slash stayed the same
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
sThresholdListenerComponent.ThresholdsReached.Clear();
// Heal both classes of damage to 0
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, -10, true));
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Burn, -20, true));
// No new thresholds reached, healing should not trigger it
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise brute damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, 10, true));
// No new thresholds reached
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise burn damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Burn, 10, 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(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
// Threshold brute 10 + burn 10
msg = sThresholdListenerComponent.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<TotalDamageClassesTrigger>(threshold.Trigger);
sThresholdListenerComponent.ThresholdsReached.Clear();
// Change triggers once to true
threshold.TriggersOnce = true;
// Heal brute and burn back to 0
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, -10, true));
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Burn, -10, true));
// No new thresholds reached from healing
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise brute damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, 10, true));
// No new thresholds reached
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise burn damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Burn, 10, true));
// No new thresholds reached as triggers once is set to true and it already triggered before
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
});
}
}
}

View File

@@ -0,0 +1,170 @@
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Destructible.Thresholds.Triggers;
using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage;
using NUnit.Framework;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using static Content.IntegrationTests.Tests.Destructible.DestructibleTestPrototypes;
namespace Content.IntegrationTests.Tests.Destructible
{
[TestFixture]
[TestOf(typeof(TotalDamageTypesTrigger))]
public class DestructibleDamageTypeTest : ContentIntegrationTest
{
[Test]
public async Task Test()
{
var server = StartServerDummyTicker(new ServerContentIntegrationOption
{
ExtraPrototypes = Prototypes,
ContentBeforeIoC = () =>
{
IoCManager.Resolve<IComponentFactory>().Register<TestThresholdListenerComponent>();
}
});
await server.WaitIdleAsync();
var sEntityManager = server.ResolveDependency<IEntityManager>();
var sMapManager = server.ResolveDependency<IMapManager>();
IEntity sDestructibleEntity;
IDamageableComponent sDamageableComponent = null;
TestThresholdListenerComponent sThresholdListenerComponent = null;
await server.WaitPost(() =>
{
var mapId = new MapId(1);
var coordinates = new MapCoordinates(0, 0, mapId);
sMapManager.CreateMap(mapId);
sDestructibleEntity = sEntityManager.SpawnEntity(DestructibleDamageTypeEntityId, coordinates);
sDamageableComponent = sDestructibleEntity.GetComponent<IDamageableComponent>();
sThresholdListenerComponent = sDestructibleEntity.GetComponent<TestThresholdListenerComponent>();
});
await server.WaitRunTicks(5);
await server.WaitAssertion(() =>
{
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
});
await server.WaitAssertion(() =>
{
// Raise blunt damage to 5
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 5, true));
// No thresholds reached yet, the earliest one is at 10 damage
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise blunt damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 5, true));
// No threshold reached, slash needs to be 10 as well
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise slash damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Slash, 10, true));
// One threshold reached, blunt 10 + slash 10
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
// Threshold blunt 10 + slash 10
var msg = sThresholdListenerComponent.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<TotalDamageTypesTrigger>(threshold.Trigger);
sThresholdListenerComponent.ThresholdsReached.Clear();
// Raise blunt damage to 20
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 10, true));
// No new thresholds reached
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise slash damage to 20
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Slash, 10, true));
// No new thresholds reached
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Lower blunt damage to 0
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, -20, true));
// No new thresholds reached, healing should not trigger it
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise blunt damage back up to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 10, true));
// 10 blunt + 10 slash threshold reached, blunt was healed and brought back to its threshold amount and slash stayed the same
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
sThresholdListenerComponent.ThresholdsReached.Clear();
// Heal both types of damage to 0
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, -10, true));
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Slash, -20, true));
// No new thresholds reached, healing should not trigger it
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise blunt damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 10, true));
// No new thresholds reached
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise slash damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Slash, 10, 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(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
// Threshold blunt 10 + slash 10
msg = sThresholdListenerComponent.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<TotalDamageTypesTrigger>(threshold.Trigger);
sThresholdListenerComponent.ThresholdsReached.Clear();
// Change triggers once to true
threshold.TriggersOnce = true;
// Heal blunt and slash back to 0
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, -10, true));
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Slash, -10, true));
// No new thresholds reached from healing
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise blunt damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 10, true));
// No new thresholds reached
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Raise slash damage to 10
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Slash, 10, true));
// No new thresholds reached as triggers once is set to true and it already triggered before
Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
});
}
}
}

View File

@@ -0,0 +1,95 @@
using System.Linq;
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Destructible.Thresholds;
using Content.Server.GameObjects.Components.Destructible.Thresholds.Behaviors;
using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage;
using NUnit.Framework;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using static Content.IntegrationTests.Tests.Destructible.DestructibleTestPrototypes;
namespace Content.IntegrationTests.Tests.Destructible
{
public class DestructibleDestructionTest : ContentIntegrationTest
{
[Test]
public async Task Test()
{
var server = StartServerDummyTicker(new ServerContentIntegrationOption
{
ExtraPrototypes = Prototypes,
ContentBeforeIoC = () =>
{
IoCManager.Resolve<IComponentFactory>().Register<TestThresholdListenerComponent>();
}
});
await server.WaitIdleAsync();
var sEntityManager = server.ResolveDependency<IEntityManager>();
var sMapManager = server.ResolveDependency<IMapManager>();
IEntity sDestructibleEntity = null;
IDamageableComponent sDamageableComponent = null;
TestThresholdListenerComponent sThresholdListenerComponent = null;
await server.WaitPost(() =>
{
var mapId = new MapId(1);
var coordinates = new MapCoordinates(0, 0, mapId);
sMapManager.CreateMap(mapId);
sDestructibleEntity = sEntityManager.SpawnEntity(DestructibleDestructionEntityId, coordinates);
sDamageableComponent = sDestructibleEntity.GetComponent<IDamageableComponent>();
sThresholdListenerComponent = sDestructibleEntity.GetComponent<TestThresholdListenerComponent>();
});
await server.WaitAssertion(() =>
{
var coordinates = sDestructibleEntity.Transform.Coordinates;
Assert.DoesNotThrow(() =>
{
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, 50, true));
});
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
var threshold = sThresholdListenerComponent.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 = sEntityManager.GetEntitiesInRange(coordinates, 2);
var found = false;
foreach (var entity in entitiesInRange)
{
if (entity.Prototype == null)
{
continue;
}
if (entity.Prototype.Name != SpawnedEntityId)
{
continue;
}
found = true;
break;
}
Assert.That(found, Is.True);
});
}
}
}

View File

@@ -0,0 +1,94 @@
namespace Content.IntegrationTests.Tests.Destructible
{
public static class DestructibleTestPrototypes
{
public const string SpawnedEntityId = "DestructibleTestsSpawnedEntity";
public const string DestructibleEntityId = "DestructibleTestsDestructibleEntity";
public const string DestructibleDestructionEntityId = "DestructibleTestsDestructibleDestructionEntity";
public const string DestructibleDamageTypeEntityId = "DestructibleTestsDestructibleDamageTypeEntity";
public const string DestructibleDamageClassEntityId = "DestructibleTestsDestructibleDamageClassEntity";
public static readonly string Prototypes = $@"
- type: entity
id: {SpawnedEntityId}
name: {SpawnedEntityId}
- type: entity
id: {DestructibleEntityId}
name: {DestructibleEntityId}
components:
- type: Damageable
- type: Destructible
thresholds:
- trigger:
!type:TotalDamageTrigger
damage: 20
triggersOnce: false
- trigger:
!type:TotalDamageTrigger
damage: 50
triggersOnce: false
behaviors:
- !type:PlaySoundBehavior
sound: /Audio/Effects/woodhit.ogg
- !type:SpawnEntitiesBehavior
spawn:
{SpawnedEntityId}:
min: 1
max: 1
- !type:DoActsBehavior
acts: [""Breakage""]
- type: TestThresholdListener
- type: entity
id: {DestructibleDestructionEntityId}
name: {DestructibleDestructionEntityId}
components:
- type: Damageable
- type: Destructible
thresholds:
- trigger:
!type:TotalDamageTrigger
damage: 50
behaviors:
- !type:PlaySoundBehavior
sound: /Audio/Effects/woodhit.ogg
- !type:SpawnEntitiesBehavior
spawn:
{SpawnedEntityId}:
min: 1
max: 1
- !type:DoActsBehavior # This must come last as it destroys the entity.
acts: [""Destruction""]
- type: TestThresholdListener
- type: entity
id: {DestructibleDamageTypeEntityId}
name: {DestructibleDamageTypeEntityId}
components:
- type: Damageable
- type: Destructible
thresholds:
- trigger:
!type:TotalDamageTypesTrigger
damage:
Blunt: 10
Slash: 10
- type: TestThresholdListener
- type: entity
id: {DestructibleDamageClassEntityId}
name: {DestructibleDamageClassEntityId}
components:
- type: Damageable
- type: Destructible
thresholds:
- trigger:
!type:TotalDamageClassesTrigger
damage:
Brute: 10
Burn: 10
- type: TestThresholdListener";
}
}

View File

@@ -1,99 +1,27 @@
using System.Collections.Generic; using System.Linq;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Destructible; using Content.Server.GameObjects.Components.Destructible;
using Content.Server.GameObjects.Components.Destructible.Thresholds; using Content.Server.GameObjects.Components.Destructible.Thresholds;
using Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior; using Content.Server.GameObjects.Components.Destructible.Thresholds.Behaviors;
using Content.Server.GameObjects.Components.Destructible.Thresholds.Triggers;
using Content.Shared.Damage; using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.Components.Damage;
using NUnit.Framework; using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Map; using Robust.Shared.Map;
using static Content.IntegrationTests.Tests.Destructible.DestructibleTestPrototypes;
namespace Content.IntegrationTests.Tests.Destructible namespace Content.IntegrationTests.Tests.Destructible
{ {
[TestFixture] [TestFixture]
[TestOf(typeof(DestructibleComponent))] [TestOf(typeof(DestructibleComponent))]
[TestOf(typeof(Threshold))] [TestOf(typeof(Threshold))]
public class DestructibleTests : ContentIntegrationTest public class DestructibleThresholdActivationTest : ContentIntegrationTest
{ {
private static readonly string SpawnedEntityId = "DestructibleTestsSpawnedEntity";
private static readonly string DestructibleEntityId = "DestructibleTestsDestructibleEntity";
private static readonly string DestructibleDestructionEntityId = "DestructibleTestsDestructibleDestructionEntity";
private static readonly string Prototypes = $@"
- type: entity
id: {SpawnedEntityId}
name: {SpawnedEntityId}
- type: entity
id: {DestructibleEntityId}
name: {DestructibleEntityId}
components:
- type: Damageable
- type: Destructible
thresholds:
20:
triggersOnce: false
50:
triggersOnce: false
behaviors:
- !type:PlaySoundBehavior
sound: /Audio/Effects/woodhit.ogg
- !type:SpawnEntitiesBehavior
spawn:
{SpawnedEntityId}:
min: 1
max: 1
- !type:DoActsBehavior
acts: [""Breakage""]
- type: TestThresholdListener
- type: entity
id: {DestructibleDestructionEntityId}
name: {DestructibleDestructionEntityId}
components:
- type: Damageable
- type: Destructible
thresholds:
50:
behaviors:
- !type:PlaySoundBehavior
sound: /Audio/Effects/woodhit.ogg
- !type:SpawnEntitiesBehavior
spawn:
{SpawnedEntityId}:
min: 1
max: 1
- !type:DoActsBehavior # This must come last as it destroys the entity.
acts: [""Destruction""]
- type: TestThresholdListener
";
private class TestThresholdListenerComponent : Component
{
public override string Name => "TestThresholdListener";
public List<DestructibleThresholdReachedMessage> ThresholdsReached { get; } = new();
public override void HandleMessage(ComponentMessage message, IComponent component)
{
base.HandleMessage(message, component);
switch (message)
{
case DestructibleThresholdReachedMessage msg:
ThresholdsReached.Add(msg);
break;
}
}
}
[Test] [Test]
public async Task TestThresholdActivation() public async Task Test()
{ {
var server = StartServerDummyTicker(new ServerContentIntegrationOption var server = StartServerDummyTicker(new ServerContentIntegrationOption
{ {
@@ -130,7 +58,7 @@ namespace Content.IntegrationTests.Tests.Destructible
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.Zero); Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
}); });
await server.WaitAssertion(() => await server.WaitAssertion(() =>
@@ -138,36 +66,31 @@ namespace Content.IntegrationTests.Tests.Destructible
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 10, true)); Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 10, true));
// No thresholds reached yet, the earliest one is at 20 damage // No thresholds reached yet, the earliest one is at 20 damage
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.Zero); Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 10, true)); Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 10, true));
// Only one threshold reached, 20 // Only one threshold reached, 20
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1)); Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
// Threshold 20
var msg = sThresholdListenerComponent.ThresholdsReached[0]; var msg = sThresholdListenerComponent.ThresholdsReached[0];
// Check that it matches the total damage dealt
Assert.That(msg.TotalDamage, Is.EqualTo(20));
var threshold = msg.Threshold; var threshold = msg.Threshold;
// Check that it matches the YAML prototype // Check that it matches the YAML prototype
Assert.That(threshold.Behaviors, Is.Empty); Assert.That(threshold.Behaviors, Is.Empty);
Assert.NotNull(threshold.Trigger);
Assert.That(threshold.Triggered, Is.True); Assert.That(threshold.Triggered, Is.True);
sThresholdListenerComponent.ThresholdsReached.Clear(); sThresholdListenerComponent.ThresholdsReached.Clear();
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 30, true)); Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 30, true));
// Only one threshold reached, 50, since 20 was already reached before // One threshold reached, 50, since 20 already triggered before and it has not been healed below that amount
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1)); Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
// Threshold 50
msg = sThresholdListenerComponent.ThresholdsReached[0]; msg = sThresholdListenerComponent.ThresholdsReached[0];
// Check that it matches the total damage dealt
Assert.That(msg.TotalDamage, Is.EqualTo(50));
threshold = msg.Threshold; threshold = msg.Threshold;
// Check that it matches the YAML prototype // Check that it matches the YAML prototype
@@ -184,6 +107,7 @@ namespace Content.IntegrationTests.Tests.Destructible
Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo(SpawnedEntityId)); 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.Min, Is.EqualTo(1));
Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1)); Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1));
Assert.NotNull(threshold.Trigger);
Assert.That(threshold.Triggered, Is.True); Assert.That(threshold.Triggered, Is.True);
sThresholdListenerComponent.ThresholdsReached.Clear(); sThresholdListenerComponent.ThresholdsReached.Clear();
@@ -191,8 +115,19 @@ namespace Content.IntegrationTests.Tests.Destructible
// Damage for 50 again, up to 100 now // Damage for 50 again, up to 100 now
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 50, true)); Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 50, true));
// No new thresholds reached as even though they don't only trigger once, the entity was not healed below the threshold // No thresholds reached as they weren't healed below the trigger amount
Assert.That(sThresholdListenerComponent.ThresholdsReached, Is.Empty); Assert.IsEmpty(sThresholdListenerComponent.ThresholdsReached);
// Heal down to 0
sDamageableComponent.Heal();
// Damage for 100, up to 100
Assert.True(sDamageableComponent.ChangeDamage(DamageType.Blunt, 100, true));
// Two thresholds reached as damage increased past the previous, 20 and 50
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(2));
sThresholdListenerComponent.ThresholdsReached.Clear();
// Heal the entity for 40 damage, down to 60 // Heal the entity for 40 damage, down to 60
sDamageableComponent.ChangeDamage(DamageType.Blunt, -40, true); sDamageableComponent.ChangeDamage(DamageType.Blunt, -40, true);
@@ -219,10 +154,6 @@ namespace Content.IntegrationTests.Tests.Destructible
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1)); Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
msg = sThresholdListenerComponent.ThresholdsReached[0]; msg = sThresholdListenerComponent.ThresholdsReached[0];
// Check that it matches the total damage dealt
Assert.That(msg.TotalDamage, Is.EqualTo(50));
threshold = msg.Threshold; threshold = msg.Threshold;
// Check that it matches the YAML prototype // Check that it matches the YAML prototype
@@ -240,6 +171,7 @@ namespace Content.IntegrationTests.Tests.Destructible
Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo(SpawnedEntityId)); 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.Min, Is.EqualTo(1));
Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1)); Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1));
Assert.NotNull(threshold.Trigger);
Assert.That(threshold.Triggered, Is.True); Assert.That(threshold.Triggered, Is.True);
// Reset thresholds reached // Reset thresholds reached
@@ -259,10 +191,9 @@ namespace Content.IntegrationTests.Tests.Destructible
// Verify the first one, should be the lowest one (20) // Verify the first one, should be the lowest one (20)
msg = sThresholdListenerComponent.ThresholdsReached[0]; msg = sThresholdListenerComponent.ThresholdsReached[0];
Assert.That(msg.ThresholdAmount, Is.EqualTo(20)); var trigger = (TotalDamageTrigger) msg.Threshold.Trigger;
Assert.NotNull(trigger);
// The total damage should be 50 Assert.That(trigger.Damage, Is.EqualTo(20));
Assert.That(msg.TotalDamage, Is.EqualTo(50));
threshold = msg.Threshold; threshold = msg.Threshold;
@@ -271,10 +202,9 @@ namespace Content.IntegrationTests.Tests.Destructible
// Verify the second one, should be the highest one (50) // Verify the second one, should be the highest one (50)
msg = sThresholdListenerComponent.ThresholdsReached[1]; msg = sThresholdListenerComponent.ThresholdsReached[1];
Assert.That(msg.ThresholdAmount, Is.EqualTo(50)); trigger = (TotalDamageTrigger) msg.Threshold.Trigger;
Assert.NotNull(trigger);
// Check that it matches the total damage dealt Assert.That(trigger.Damage, Is.EqualTo(50));
Assert.That(msg.TotalDamage, Is.EqualTo(50));
threshold = msg.Threshold; threshold = msg.Threshold;
@@ -292,6 +222,7 @@ namespace Content.IntegrationTests.Tests.Destructible
Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo(SpawnedEntityId)); 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.Min, Is.EqualTo(1));
Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1)); Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1));
Assert.NotNull(threshold.Trigger);
Assert.That(threshold.Triggered, Is.True); Assert.That(threshold.Triggered, Is.True);
// Reset thresholds reached // Reset thresholds reached
@@ -304,8 +235,9 @@ namespace Content.IntegrationTests.Tests.Destructible
Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(0)); Assert.That(sDamageableComponent.TotalDamage, Is.EqualTo(0));
// Set both thresholds to only trigger once // Set both thresholds to only trigger once
foreach (var destructibleThreshold in sDestructibleComponent.LowestToHighestThresholds.Values) foreach (var destructibleThreshold in sDestructibleComponent.Thresholds)
{ {
Assert.NotNull(destructibleThreshold.Trigger);
destructibleThreshold.TriggersOnce = true; destructibleThreshold.TriggersOnce = true;
} }
@@ -319,8 +251,9 @@ namespace Content.IntegrationTests.Tests.Destructible
Assert.That(sThresholdListenerComponent.ThresholdsReached, Is.Empty); Assert.That(sThresholdListenerComponent.ThresholdsReached, Is.Empty);
// Set both thresholds to trigger multiple times // Set both thresholds to trigger multiple times
foreach (var destructibleThreshold in sDestructibleComponent.LowestToHighestThresholds.Values) foreach (var destructibleThreshold in sDestructibleComponent.Thresholds)
{ {
Assert.NotNull(destructibleThreshold.Trigger);
destructibleThreshold.TriggersOnce = false; destructibleThreshold.TriggersOnce = false;
} }
@@ -331,84 +264,5 @@ namespace Content.IntegrationTests.Tests.Destructible
Assert.That(sThresholdListenerComponent.ThresholdsReached, Is.Empty); Assert.That(sThresholdListenerComponent.ThresholdsReached, Is.Empty);
}); });
} }
[Test]
public async Task DestructibleDestructionTest()
{
var server = StartServerDummyTicker(new ServerContentIntegrationOption
{
ExtraPrototypes = Prototypes,
ContentBeforeIoC = () =>
{
IoCManager.Resolve<IComponentFactory>().Register<TestThresholdListenerComponent>();
}
});
await server.WaitIdleAsync();
var sEntityManager = server.ResolveDependency<IEntityManager>();
var sMapManager = server.ResolveDependency<IMapManager>();
IEntity sDestructibleEntity = null;
IDamageableComponent sDamageableComponent = null;
DestructibleComponent sDestructibleComponent = null;
TestThresholdListenerComponent sThresholdListenerComponent = null;
await server.WaitPost(() =>
{
var mapId = new MapId(1);
var coordinates = new MapCoordinates(0, 0, mapId);
sMapManager.CreateMap(mapId);
sDestructibleEntity = sEntityManager.SpawnEntity(DestructibleDestructionEntityId, coordinates);
sDamageableComponent = sDestructibleEntity.GetComponent<IDamageableComponent>();
sDestructibleComponent = sDestructibleEntity.GetComponent<DestructibleComponent>();
sThresholdListenerComponent = sDestructibleEntity.GetComponent<TestThresholdListenerComponent>();
});
await server.WaitAssertion(() =>
{
var coordinates = sDestructibleEntity.Transform.Coordinates;
Assert.DoesNotThrow(() =>
{
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, 50, true));
});
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
var threshold = sThresholdListenerComponent.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 = sEntityManager.GetEntitiesInRange(coordinates, 2);
var found = false;
foreach (var entity in entitiesInRange)
{
if (entity.Prototype == null)
{
continue;
}
if (entity.Prototype.Name != SpawnedEntityId)
{
continue;
}
found = true;
break;
}
Assert.That(found, Is.True);
});
}
} }
} }

View File

@@ -0,0 +1,26 @@
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Destructible;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
namespace Content.IntegrationTests.Tests.Destructible
{
public class TestThresholdListenerComponent : Component
{
public override string Name => "TestThresholdListener";
public List<DestructibleThresholdReachedMessage> ThresholdsReached { get; } = new();
public override void HandleMessage(ComponentMessage message, IComponent component)
{
base.HandleMessage(message, component);
switch (message)
{
case DestructibleThresholdReachedMessage msg:
ThresholdsReached.Add(msg);
break;
}
}
}
}

View File

@@ -22,22 +22,15 @@ namespace Content.Server.GameObjects.Components.Destructible
public override string Name => "Destructible"; public override string Name => "Destructible";
[ViewVariables] [ViewVariables] private List<Threshold> _thresholds = new();
private SortedDictionary<int, Threshold> _lowestToHighestThresholds = new();
[ViewVariables] private int PreviousTotalDamage { get; set; } public IReadOnlyList<Threshold> Thresholds => _thresholds;
public IReadOnlyDictionary<int, Threshold> LowestToHighestThresholds => _lowestToHighestThresholds;
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
base.ExposeData(serializer); base.ExposeData(serializer);
serializer.DataReadWriteFunction( serializer.DataField(ref _thresholds, "thresholds", new List<Threshold>());
"thresholds",
new Dictionary<int, Threshold>(),
thresholds => _lowestToHighestThresholds = new SortedDictionary<int, Threshold>(thresholds),
() => new Dictionary<int, Threshold>(_lowestToHighestThresholds));
} }
public override void Initialize() public override void Initialize()
@@ -60,32 +53,17 @@ namespace Content.Server.GameObjects.Components.Destructible
break; break;
} }
foreach (var (damage, threshold) in _lowestToHighestThresholds) foreach (var threshold in _thresholds)
{ {
if (threshold.Triggered) if (threshold.Reached(msg.Damageable, _destructibleSystem))
{ {
if (threshold.TriggersOnce) var thresholdMessage = new DestructibleThresholdReachedMessage(this, threshold);
{
continue;
}
if (PreviousTotalDamage >= damage)
{
continue;
}
}
if (msg.Damageable.TotalDamage >= damage)
{
var thresholdMessage = new DestructibleThresholdReachedMessage(this, threshold, msg.Damageable.TotalDamage, damage);
SendMessage(thresholdMessage); SendMessage(thresholdMessage);
threshold.Trigger(Owner, _destructibleSystem); threshold.Execute(Owner, _destructibleSystem);
} }
} }
PreviousTotalDamage = msg.Damageable.TotalDamage;
break; break;
} }
} }

View File

@@ -5,26 +5,14 @@ namespace Content.Server.GameObjects.Components.Destructible
{ {
public class DestructibleThresholdReachedMessage : ComponentMessage public class DestructibleThresholdReachedMessage : ComponentMessage
{ {
public DestructibleThresholdReachedMessage(DestructibleComponent parent, Threshold threshold, int totalDamage, int thresholdAmount) public DestructibleThresholdReachedMessage(DestructibleComponent parent, Threshold threshold)
{ {
Parent = parent; Parent = parent;
Threshold = threshold; Threshold = threshold;
TotalDamage = totalDamage;
ThresholdAmount = thresholdAmount;
} }
public DestructibleComponent Parent { get; } public DestructibleComponent Parent { get; }
public Threshold Threshold { get; } public Threshold Threshold { get; }
/// <summary>
/// The amount of total damage currently had that triggered this threshold.
/// </summary>
public int TotalDamage { get; }
/// <summary>
/// The amount of damage at which this threshold triggers.
/// </summary>
public int ThresholdAmount { get; }
} }
} }

View File

@@ -1,10 +1,12 @@
using Content.Server.GameObjects.EntitySystems; using System;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behaviors
{ {
[Serializable]
public class DoActsBehavior : IThresholdBehavior public class DoActsBehavior : IThresholdBehavior
{ {
private int _acts; private int _acts;
@@ -29,7 +31,7 @@ namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior
return (_acts & (int) act) != 0; return (_acts & (int) act) != 0;
} }
public void Trigger(IEntity owner, DestructibleSystem system) public void Execute(IEntity owner, DestructibleSystem system)
{ {
if (HasAct(ThresholdActs.Breakage)) if (HasAct(ThresholdActs.Breakage))
{ {

View File

@@ -4,7 +4,7 @@ using JetBrains.Annotations;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behaviors
{ {
[UsedImplicitly] [UsedImplicitly]
public class GibBehavior : IThresholdBehavior public class GibBehavior : IThresholdBehavior
@@ -16,7 +16,7 @@ namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior
serializer.DataField(ref _recursive, "recursive", true); serializer.DataField(ref _recursive, "recursive", true);
} }
public void Trigger(IEntity owner, DestructibleSystem system) public void Execute(IEntity owner, DestructibleSystem system)
{ {
if (owner.TryGetComponent(out IBody body)) if (owner.TryGetComponent(out IBody body))
{ {

View File

@@ -2,18 +2,18 @@
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Serialization; using Robust.Shared.Interfaces.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behaviors
{ {
public interface IThresholdBehavior : IExposeData public interface IThresholdBehavior : IExposeData
{ {
/// <summary> /// <summary>
/// Triggers this behavior. /// Executes this behavior.
/// </summary> /// </summary>
/// <param name="owner">The entity that owns this behavior.</param> /// <param name="owner">The entity that owns this behavior.</param>
/// <param name="system"> /// <param name="system">
/// An instance of <see cref="DestructibleSystem"/> to pull dependencies /// An instance of <see cref="DestructibleSystem"/> to pull dependencies
/// and other systems from. /// and other systems from.
/// </param> /// </param>
void Trigger(IEntity owner, DestructibleSystem system); void Execute(IEntity owner, DestructibleSystem system);
} }
} }

View File

@@ -1,10 +1,12 @@
using Content.Server.GameObjects.EntitySystems; using System;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Audio; using Content.Shared.Audio;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behaviors
{ {
[Serializable]
public class PlaySoundBehavior : IThresholdBehavior public class PlaySoundBehavior : IThresholdBehavior
{ {
/// <summary> /// <summary>
@@ -17,7 +19,7 @@ namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior
serializer.DataField(this, x => x.Sound, "sound", string.Empty); serializer.DataField(this, x => x.Sound, "sound", string.Empty);
} }
public void Trigger(IEntity owner, DestructibleSystem system) public void Execute(IEntity owner, DestructibleSystem system)
{ {
if (string.IsNullOrEmpty(Sound)) if (string.IsNullOrEmpty(Sound))
{ {

View File

@@ -1,10 +1,12 @@
using Content.Server.GameObjects.EntitySystems; using System;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Audio; using Content.Shared.Audio;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behaviors
{ {
[Serializable]
public class PlaySoundCollectionBehavior : IThresholdBehavior public class PlaySoundCollectionBehavior : IThresholdBehavior
{ {
/// <summary> /// <summary>
@@ -17,7 +19,7 @@ namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior
serializer.DataField(this, x => x.SoundCollection, "soundCollection", string.Empty); serializer.DataField(this, x => x.SoundCollection, "soundCollection", string.Empty);
} }
public void Trigger(IEntity owner, DestructibleSystem system) public void Execute(IEntity owner, DestructibleSystem system)
{ {
if (string.IsNullOrEmpty(SoundCollection)) if (string.IsNullOrEmpty(SoundCollection))
{ {

View File

@@ -1,4 +1,5 @@
#nullable enable #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.Components.Stack;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
@@ -6,8 +7,9 @@ using Content.Shared.Utility;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behaviors
{ {
[Serializable]
public class SpawnEntitiesBehavior : IThresholdBehavior public class SpawnEntitiesBehavior : IThresholdBehavior
{ {
/// <summary> /// <summary>
@@ -20,7 +22,7 @@ namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior
serializer.DataField(this, x => x.Spawn, "spawn", new Dictionary<string, MinMax>()); serializer.DataField(this, x => x.Spawn, "spawn", new Dictionary<string, MinMax>());
} }
public void Trigger(IEntity owner, DestructibleSystem system) public void Execute(IEntity owner, DestructibleSystem system)
{ {
foreach (var (entityId, minMax) in Spawn) foreach (var (entityId, minMax) in Spawn)
{ {

View File

@@ -6,14 +6,14 @@ using JetBrains.Annotations;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Behaviors
{ {
[UsedImplicitly] [UsedImplicitly]
public class SpillBehavior : IThresholdBehavior public class SpillBehavior : IThresholdBehavior
{ {
public void ExposeData(ObjectSerializer serializer) { } public void ExposeData(ObjectSerializer serializer) { }
public void Trigger(IEntity owner, DestructibleSystem system) public void Execute(IEntity owner, DestructibleSystem system)
{ {
if (!owner.TryGetComponent(out SolutionContainerComponent? solutionContainer)) if (!owner.TryGetComponent(out SolutionContainerComponent? solutionContainer))
return; return;

View File

@@ -1,9 +1,11 @@
using Robust.Shared.Interfaces.Serialization; using System;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds namespace Content.Server.GameObjects.Components.Destructible.Thresholds
{ {
[Serializable]
public struct MinMax : IExposeData public struct MinMax : IExposeData
{ {
[ViewVariables] [ViewVariables]

View File

@@ -1,7 +1,9 @@
#nullable enable #nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.GameObjects.Components.Destructible.Thresholds.Behavior; using Content.Server.GameObjects.Components.Destructible.Thresholds.Behaviors;
using Content.Server.GameObjects.Components.Destructible.Thresholds.Triggers;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Damage;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Serialization; using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
@@ -13,6 +15,12 @@ namespace Content.Server.GameObjects.Components.Destructible.Thresholds
{ {
private List<IThresholdBehavior> _behaviors = new(); private List<IThresholdBehavior> _behaviors = new();
/// <summary>
/// Whether or not this threshold was triggered in the previous call to
/// <see cref="Reached"/>.
/// </summary>
[ViewVariables] public bool OldTriggered { get; private set; }
/// <summary> /// <summary>
/// Whether or not this threshold has already been triggered. /// Whether or not this threshold has already been triggered.
/// </summary> /// </summary>
@@ -26,6 +34,11 @@ namespace Content.Server.GameObjects.Components.Destructible.Thresholds
/// </summary> /// </summary>
[ViewVariables] public bool TriggersOnce { get; set; } [ViewVariables] public bool TriggersOnce { get; set; }
/// <summary>
/// The trigger that decides if this threshold has been reached.
/// </summary>
[ViewVariables] public IThresholdTrigger? Trigger { get; set; }
/// <summary> /// <summary>
/// Behaviors to activate once this threshold is triggered. /// Behaviors to activate once this threshold is triggered.
/// </summary> /// </summary>
@@ -35,9 +48,37 @@ namespace Content.Server.GameObjects.Components.Destructible.Thresholds
{ {
serializer.DataField(this, x => x.Triggered, "triggered", false); serializer.DataField(this, x => x.Triggered, "triggered", false);
serializer.DataField(this, x => x.TriggersOnce, "triggersOnce", false); serializer.DataField(this, x => x.TriggersOnce, "triggersOnce", false);
serializer.DataField(this, x => x.Trigger, "trigger", null);
serializer.DataField(ref _behaviors, "behaviors", new List<IThresholdBehavior>()); serializer.DataField(ref _behaviors, "behaviors", new List<IThresholdBehavior>());
} }
public bool Reached(IDamageableComponent damageable, DestructibleSystem system)
{
if (Trigger == null)
{
return false;
}
if (Triggered && TriggersOnce)
{
return false;
}
if (OldTriggered)
{
OldTriggered = Trigger.Reached(damageable, system);
return false;
}
if (!Trigger.Reached(damageable, system))
{
return false;
}
OldTriggered = true;
return true;
}
/// <summary> /// <summary>
/// Triggers this threshold. /// Triggers this threshold.
/// </summary> /// </summary>
@@ -46,7 +87,7 @@ namespace Content.Server.GameObjects.Components.Destructible.Thresholds
/// An instance of <see cref="DestructibleSystem"/> to get dependency and /// An instance of <see cref="DestructibleSystem"/> to get dependency and
/// system references from, if relevant. /// system references from, if relevant.
/// </param> /// </param>
public void Trigger(IEntity owner, DestructibleSystem system) public void Execute(IEntity owner, DestructibleSystem system)
{ {
Triggered = true; Triggered = true;
@@ -56,7 +97,7 @@ namespace Content.Server.GameObjects.Components.Destructible.Thresholds
if (owner.Deleted) if (owner.Deleted)
return; return;
behavior.Trigger(owner, system); behavior.Execute(owner, system);
} }
} }
} }

View File

@@ -0,0 +1,21 @@
#nullable enable
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Damage;
using Robust.Shared.Interfaces.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Triggers
{
public interface IThresholdTrigger : IExposeData
{
/// <summary>
/// Checks if this trigger has been reached.
/// </summary>
/// <param name="damageable">The damageable component to check with.</param>
/// <param name="system">
/// An instance of <see cref="DestructibleSystem"/> to pull
/// dependencies from, if any.
/// </param>
/// <returns>true if this trigger has been reached, false otherwise.</returns>
bool Reached(IDamageableComponent damageable, DestructibleSystem system);
}
}

View File

@@ -0,0 +1,47 @@
#nullable enable
using System;
using System.Collections.Generic;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage;
using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Triggers
{
/// <summary>
/// A trigger that will activate when all of the damage classes received
/// are above the specified threshold.
/// </summary>
[Serializable]
public class TotalDamageClassesTrigger : IThresholdTrigger
{
/// <summary>
/// The amount of damage at which this threshold will trigger.
/// The damage requirements of all <see cref="DamageClass"/> must be met.
/// </summary>
private Dictionary<DamageClass, int> Damage { get; set; } = new();
public void ExposeData(ObjectSerializer serializer)
{
serializer.DataField(this, x => x.Damage, "damage", new Dictionary<DamageClass, int>());
}
public bool Reached(IDamageableComponent damageable, DestructibleSystem system)
{
foreach (var (type, damageRequired) in Damage)
{
if (!damageable.TryGetDamage(type, out var damageReceived))
{
return false;
}
if (damageReceived < damageRequired)
{
return false;
}
}
return true;
}
}
}

View File

@@ -0,0 +1,31 @@
#nullable enable
using System;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Damage;
using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Triggers
{
/// <summary>
/// A trigger that will activate when the amount of total damage received
/// is above the specified threshold.
/// </summary>
[Serializable]
public class TotalDamageTrigger : IThresholdTrigger
{
/// <summary>
/// The amount of total damage at which this threshold will trigger.
/// </summary>
public int Damage { get; private set; }
public void ExposeData(ObjectSerializer serializer)
{
serializer.DataField(this, x => x.Damage, "damage", 0);
}
public bool Reached(IDamageableComponent damageable, DestructibleSystem system)
{
return damageable.TotalDamage >= Damage;
}
}
}

View File

@@ -0,0 +1,47 @@
#nullable enable
using System;
using System.Collections.Generic;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage;
using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Destructible.Thresholds.Triggers
{
/// <summary>
/// A trigger that will activate when all of the damage types received
/// are above the specified threshold.
/// </summary>
[Serializable]
public class TotalDamageTypesTrigger : IThresholdTrigger
{
/// <summary>
/// The amount of damage at which this threshold will trigger.
/// The damage requirements of all <see cref="DamageType"/> must be met.
/// </summary>
private Dictionary<DamageType, int> Damage { get; set; } = new();
public void ExposeData(ObjectSerializer serializer)
{
serializer.DataField(this, x => x.Damage, "damage", new Dictionary<DamageType, int>());
}
public bool Reached(IDamageableComponent damageable, DestructibleSystem system)
{
foreach (var (type, damageRequired) in Damage)
{
if (!damageable.TryGetDamage(type, out var damageReceived))
{
return false;
}
if (damageReceived < damageRequired)
{
return false;
}
}
return true;
}
}
}

View File

@@ -1,5 +1,6 @@
#nullable enable #nullable enable
using System; using System;
using System.Linq;
using Content.Server.Utility; using Content.Server.Utility;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.Components;
@@ -7,6 +8,7 @@ using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
using Content.Server.GameObjects.Components.Destructible; using Content.Server.GameObjects.Components.Destructible;
using Content.Server.GameObjects.Components.Destructible.Thresholds.Triggers;
using Content.Shared.Utility; using Content.Shared.Utility;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.GameObjects.EntitySystems; using Robust.Server.GameObjects.EntitySystems;
@@ -22,7 +24,6 @@ namespace Content.Server.GameObjects.Components
[ComponentReference(typeof(SharedWindowComponent))] [ComponentReference(typeof(SharedWindowComponent))]
public class WindowComponent : SharedWindowComponent, IExamine, IInteractHand public class WindowComponent : SharedWindowComponent, IExamine, IInteractHand
{ {
public override void HandleMessage(ComponentMessage message, IComponent? component) public override void HandleMessage(ComponentMessage message, IComponent? component)
{ {
base.HandleMessage(message, component); base.HandleMessage(message, component);
@@ -40,26 +41,52 @@ namespace Content.Server.GameObjects.Components
private void UpdateVisuals(int currentDamage) private void UpdateVisuals(int currentDamage)
{ {
if (Owner.TryGetComponent(out AppearanceComponent? appearance)) if (Owner.TryGetComponent(out AppearanceComponent? appearance) &&
Owner.TryGetComponent(out DestructibleComponent? destructible))
{ {
if (Owner.TryGetComponent(out DestructibleComponent? destructible)) foreach (var threshold in destructible.Thresholds)
{ {
var damageThreshold = destructible.LowestToHighestThresholds.FirstOrNull()?.Key; if (threshold.Trigger is not TotalDamageTrigger trigger)
if (damageThreshold == null) return; {
appearance.SetData(WindowVisuals.Damage, (float) currentDamage / damageThreshold); continue;
}
appearance.SetData(WindowVisuals.Damage, (float) currentDamage / trigger.Damage);
} }
} }
} }
void IExamine.Examine(FormattedMessage message, bool inDetailsRange) void IExamine.Examine(FormattedMessage message, bool inDetailsRange)
{ {
var damage = Owner.GetComponentOrNull<IDamageableComponent>()?.TotalDamage; if (!Owner.TryGetComponent(out IDamageableComponent? damageable) ||
var damageThreshold = Owner.GetComponentOrNull<DestructibleComponent>()?.LowestToHighestThresholds.FirstOrNull()?.Key; !Owner.TryGetComponent(out DestructibleComponent? destructible))
if (damage == null || damageThreshold == null) return; {
var fraction = ((damage == 0 || damageThreshold == 0) return;
}
var damage = damageable.TotalDamage;
TotalDamageTrigger? trigger = null;
// TODO: Pretend this does not exist until https://github.com/space-wizards/space-station-14/pull/2783 is merged
foreach (var threshold in destructible.Thresholds)
{
if ((trigger = threshold.Trigger as TotalDamageTrigger) != null)
{
break;
}
}
if (trigger == null)
{
return;
}
var damageThreshold = trigger.Damage;
var fraction = damage == 0 || damageThreshold == 0
? 0f ? 0f
: (float) damage / damageThreshold); : (float) damage / damageThreshold;
var level = Math.Min(ContentHelpers.RoundToLevels((double) fraction, 1, 7), 5); var level = Math.Min(ContentHelpers.RoundToLevels((double) fraction, 1, 7), 5);
switch (level) switch (level)
{ {
case 0: case 0:

View File

@@ -13,6 +13,7 @@ namespace Content.Server.GameObjects.EntitySystems
[Dependency] public readonly IRobustRandom Random = default!; [Dependency] public readonly IRobustRandom Random = default!;
public AudioSystem AudioSystem { get; private set; } public AudioSystem AudioSystem { get; private set; }
public ActSystem ActSystem { get; private set; } public ActSystem ActSystem { get; private set; }
public override void Initialize() public override void Initialize()

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Damage namespace Content.Shared.Damage

View File

@@ -60,10 +60,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
500: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 500
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
mode: NoSprite mode: NoSprite

View File

@@ -25,9 +25,11 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
75: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 75
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
placement: placement:
mode: SnapgridCenter mode: SnapgridCenter

View File

@@ -23,17 +23,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
30: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 30
sound: /Audio/Effects/woodhit.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/woodhit.ogg
WoodPlank: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 WoodPlank:
- !type:DoActsBehavior min: 1
acts: ["Destruction"] max: 1
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Occluder - type: Occluder
sizeX: 32 sizeX: 32

View File

@@ -24,10 +24,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 50
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: UserInterface - type: UserInterface
interfaces: interfaces:
- key: enum.InstrumentUiKey.Key - key: enum.InstrumentUiKey.Key

View File

@@ -15,10 +15,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: ShuttleController - type: ShuttleController
- type: Strap - type: Strap
position: Stand position: Stand

View File

@@ -34,10 +34,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 50
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: entity - type: entity
name: chair name: chair

View File

@@ -31,17 +31,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
30: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 30
sound: /Audio/Effects/metalbreak.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/metalbreak.ogg
SteelSheet1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 SteelSheet1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: entity - type: entity
id: Shelf id: Shelf
@@ -76,14 +78,16 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
30: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 30
sound: /Audio/Effects/metalbreak.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/metalbreak.ogg
SteelSheet1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 SteelSheet1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]

View File

@@ -39,17 +39,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
15: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 15
sound: /Audio/Effects/metalbreak.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/metalbreak.ogg
SteelSheet1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 SteelSheet1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: entity - type: entity
id: TableFrame id: TableFrame
@@ -65,17 +67,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
1: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 1
sound: /Audio/Effects/metalbreak.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/metalbreak.ogg
SteelSheet1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 SteelSheet1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Construction - type: Construction
graph: Tables graph: Tables
node: TableFrame node: TableFrame
@@ -94,17 +98,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
1: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 1
sound: /Audio/Effects/metalbreak.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/metalbreak.ogg
SteelSheet1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 SteelSheet1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: entity - type: entity
id: TableMetal id: TableMetal
@@ -120,17 +126,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
15: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 15
sound: /Audio/Effects/metalbreak.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/metalbreak.ogg
SteelSheet1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 SteelSheet1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Construction - type: Construction
graph: Tables graph: Tables
node: MetalTable node: MetalTable
@@ -149,17 +157,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
75: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 75
sound: /Audio/Effects/metalbreak.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/metalbreak.ogg
SteelSheet1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 SteelSheet1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Construction - type: Construction
graph: Tables graph: Tables
node: ReinforcedTable node: ReinforcedTable
@@ -178,17 +188,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
5: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 5
sound: /Audio/Effects/glass_break2.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/glass_break2.ogg
ShardGlass: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 ShardGlass:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Construction - type: Construction
graph: Tables graph: Tables
node: GlassTable node: GlassTable
@@ -207,17 +219,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
20: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 20
sound: /Audio/Effects/glass_break2.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/glass_break2.ogg
ShardGlass: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 ShardGlass:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Construction - type: Construction
graph: Tables graph: Tables
node: RGlassTable node: RGlassTable
@@ -236,17 +250,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
15: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 15
sound: /Audio/Effects/woodhit.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/woodhit.ogg
WoodPlank: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 WoodPlank:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Construction - type: Construction
graph: Tables graph: Tables
node: WoodTable node: WoodTable
@@ -265,17 +281,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
15: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 15
sound: /Audio/Effects/woodhit.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/woodhit.ogg
WoodPlank: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 WoodPlank:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Construction - type: Construction
graph: Tables graph: Tables
node: PokerTable node: PokerTable
@@ -294,12 +312,14 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 50
sound: /Audio/Effects/picaxe2.ogg behaviors:
- !type:DoActsBehavior - !type:PlaySoundBehavior
acts: [ "Destruction" ] sound: /Audio/Effects/picaxe2.ogg
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: entity - type: entity
id: TableDebug id: TableDebug
@@ -315,7 +335,9 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
1: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 1
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]

View File

@@ -19,10 +19,12 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: GasCanisterPort - type: GasCanisterPort
- type: entity - type: entity

View File

@@ -13,10 +13,12 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: GasCanister - type: GasCanister
- type: Anchorable - type: Anchorable
- type: Pullable - type: Pullable

View File

@@ -13,10 +13,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Sprite - type: Sprite
netsync: false netsync: false
sprite: Constructible/Atmos/gasfilter.rsi sprite: Constructible/Atmos/gasfilter.rsi

View File

@@ -23,8 +23,10 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 50
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: KitchenSpike - type: KitchenSpike

View File

@@ -1,4 +1,4 @@
- type: entity - type: entity
abstract: true abstract: true
id: PipeBase id: PipeBase
name: Pipe name: Pipe
@@ -14,10 +14,12 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Sprite - type: Sprite
netsync: false netsync: false
- type: Appearance - type: Appearance

View File

@@ -13,10 +13,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Sprite - type: Sprite
netsync: false netsync: false
sprite: Constructible/Atmos/pump.rsi sprite: Constructible/Atmos/pump.rsi
@@ -44,4 +46,3 @@
- type: PressurePump - type: PressurePump
inletDirection: West inletDirection: West
outletDirection: East outletDirection: East

View File

@@ -13,10 +13,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Sprite - type: Sprite
netsync: false netsync: false
sprite: Constructible/Atmos/scrubber.rsi sprite: Constructible/Atmos/scrubber.rsi

View File

@@ -13,10 +13,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Sprite - type: Sprite
netsync: false netsync: false
sprite: Constructible/Atmos/vent.rsi sprite: Constructible/Atmos/vent.rsi

View File

@@ -98,10 +98,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: BreakableConstruction - type: BreakableConstruction
node: monitorBroken node: monitorBroken
- type: Sprite - type: Sprite

View File

@@ -31,10 +31,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Breakage"] behaviors:
- !type:DoActsBehavior
acts: ["Breakage"]
- type: Anchorable - type: Anchorable
- type: entity - type: entity

View File

@@ -257,10 +257,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Breakage"] behaviors:
- !type:DoActsBehavior
acts: ["Breakage"]
- type: Anchorable - type: Anchorable
- type: Pullable - type: Pullable
- type: ClientEntitySpawner - type: ClientEntitySpawner

View File

@@ -32,10 +32,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 50
acts: ["Breakage"] behaviors:
- !type:DoActsBehavior
acts: ["Breakage"]
- type: UserInterface - type: UserInterface
interfaces: interfaces:
- key: enum.VendingMachineUiKey.Key - key: enum.VendingMachineUiKey.Key

View File

@@ -22,10 +22,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: SubFloorHide - type: SubFloorHide
- type: entity - type: entity
@@ -53,15 +55,17 @@
wireType: HighVoltage wireType: HighVoltage
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 100
spawn: behaviors:
HVWireStack1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 HVWireStack1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: entity - type: entity
parent: WireBase parent: WireBase
@@ -90,15 +94,17 @@
wireType: MediumVoltage wireType: MediumVoltage
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 100
spawn: behaviors:
MVWireStack1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 MVWireStack1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: entity - type: entity
parent: WireBase parent: WireBase
@@ -129,15 +135,17 @@
wireType: Apc wireType: Apc
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 100
spawn: behaviors:
ApcExtensionCableStack1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 ApcExtensionCableStack1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
#Dummy wires #Dummy wires

View File

@@ -25,10 +25,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
500: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 500
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: SnapGrid - type: SnapGrid
offset: Center offset: Center
- type: Anchorable - type: Anchorable

View File

@@ -25,15 +25,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
500: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 500
spawn: behaviors:
AMEPart: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 AMEPart:
- !type:DoActsBehavior min: 1
acts: ["Destruction"] max: 1
- !type:DoActsBehavior
acts: ["Destruction"]
- type: SnapGrid - type: SnapGrid
offset: Center offset: Center
- type: Airtight - type: Airtight

View File

@@ -34,10 +34,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Appearance - type: Appearance
visuals: visuals:
- type: CloningPodVisualizer - type: CloningPodVisualizer

View File

@@ -34,10 +34,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Appearance - type: Appearance
visuals: visuals:
- type: MedicalScannerVisualizer - type: MedicalScannerVisualizer

View File

@@ -21,10 +21,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
75: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 75
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Anchorable - type: Anchorable
- type: Pullable - type: Pullable
- type: PowerReceiver - type: PowerReceiver

View File

@@ -35,15 +35,17 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 50
spawn: behaviors:
chem_master_broken: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 chem_master_broken:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: UserInterface - type: UserInterface
interfaces: interfaces:
- key: enum.ChemMasterUiKey.Key - key: enum.ChemMasterUiKey.Key
@@ -84,15 +86,17 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
25: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 25
spawn: behaviors:
SteelSheet1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 SteelSheet1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: UserInterface - type: UserInterface
interfaces: interfaces:
- key: enum.ChemMasterUiKey.Key - key: enum.ChemMasterUiKey.Key

View File

@@ -17,10 +17,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Breakage"] behaviors:
- !type:DoActsBehavior
acts: ["Breakage"]
- type: Rotatable - type: Rotatable
- type: Pullable - type: Pullable
@@ -151,10 +153,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Appearance - type: Appearance
visuals: visuals:
- type: DisposalUnitVisualizer - type: DisposalUnitVisualizer
@@ -392,10 +396,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Appearance - type: Appearance
visuals: visuals:
- type: DisposalUnitVisualizer - type: DisposalUnitVisualizer

View File

@@ -33,10 +33,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
150: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 150
acts: ["Breakage"] behaviors:
- !type:DoActsBehavior
acts: ["Breakage"]
- type: GravityGenerator - type: GravityGenerator
- type: UserInterface - type: UserInterface
interfaces: interfaces:

View File

@@ -27,10 +27,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 50
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Sprite - type: Sprite
sprite: Constructible/Hydroponics/hydro_tools.rsi sprite: Constructible/Hydroponics/hydro_tools.rsi
state: soil state: soil

View File

@@ -43,10 +43,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Appearance - type: Appearance
visuals: visuals:
- type: StorageVisualizer - type: StorageVisualizer

View File

@@ -39,10 +39,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Appearance - type: Appearance
visuals: visuals:
- type: StorageVisualizer - type: StorageVisualizer

View File

@@ -27,10 +27,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
10: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 10
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: SolutionContainer - type: SolutionContainer
maxVol: 1500 maxVol: 1500
caps: Drainable caps: Drainable

View File

@@ -18,10 +18,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Occluder - type: Occluder
sizeX: 32 sizeX: 32
sizeY: 32 sizeY: 32

View File

@@ -30,15 +30,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 50
spawn: behaviors:
SteelSheet1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 SteelSheet1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: SnapGrid - type: SnapGrid
offset: Edge offset: Edge
placement: placement:

View File

@@ -40,10 +40,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 50
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: entity - type: entity
name: small light name: small light
@@ -69,10 +71,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
25: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 25
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: entity - type: entity
name: unpowered small light name: unpowered small light
@@ -90,7 +94,9 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
25: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 25
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]

View File

@@ -29,10 +29,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 100
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: BreakableConstruction - type: BreakableConstruction
node: start node: start
- type: SnapGrid - type: SnapGrid

View File

@@ -12,10 +12,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
5: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 5
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Sprite - type: Sprite
drawdepth: WallTops drawdepth: WallTops
sprite: Constructible/Misc/decals.rsi sprite: Constructible/Misc/decals.rsi

View File

@@ -48,15 +48,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: brick base: brick
@@ -74,15 +76,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: clock base: clock
@@ -100,15 +104,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: clown base: clown
@@ -127,15 +133,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: cult base: cult
@@ -153,15 +161,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: debug base: debug
@@ -179,15 +189,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: diamond base: diamond
@@ -206,15 +218,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: gold base: gold
@@ -232,15 +246,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: ice base: ice
@@ -258,15 +274,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: metal base: metal
@@ -284,15 +302,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: plasma base: plasma
@@ -310,15 +330,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: plastic base: plastic
@@ -341,10 +363,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
600: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 600
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: BreakableConstruction - type: BreakableConstruction
node: girder node: girder
- type: ReinforcedWall - type: ReinforcedWall
@@ -369,15 +393,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
1000: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 1000
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: riveted base: riveted
@@ -395,15 +421,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: sandstone base: sandstone
@@ -421,15 +449,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: silver base: silver
@@ -451,10 +481,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 300
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: BreakableConstruction - type: BreakableConstruction
node: girder node: girder
destroySound: /Audio/Effects/metalbreak.ogg destroySound: /Audio/Effects/metalbreak.ogg
@@ -475,15 +507,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: uranium base: uranium
@@ -501,15 +535,17 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
300: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 300
spawn: behaviors:
Girder: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 Girder:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: IconSmooth - type: IconSmooth
key: walls key: walls
base: wood base: wood

View File

@@ -30,17 +30,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
15: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundCollectionBehavior damage: 15
soundCollection: GlassBreak behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundCollectionBehavior
spawn: soundCollection: GlassBreak
ShardGlass: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 2 ShardGlass:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 2
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: SnapGrid - type: SnapGrid
offset: Center offset: Center
- type: Airtight - type: Airtight
@@ -67,17 +69,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
75: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundCollectionBehavior damage: 75
soundCollection: GlassBreak behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundCollectionBehavior
spawn: soundCollection: GlassBreak
ShardGlassReinforced: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 2 ShardGlassReinforced:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 2
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Window - type: Window
base: rwindow base: rwindow
- type: Construction - type: Construction
@@ -98,17 +102,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
100: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundCollectionBehavior damage: 100
soundCollection: GlassBreak behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundCollectionBehavior
spawn: soundCollection: GlassBreak
ShardGlassPhoron: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 2 ShardGlassPhoron:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 2
- !type:DoActsBehavior
acts: [ "Destruction" ]
resistances: metallicResistances resistances: metallicResistances
- type: Window - type: Window
base: pwindow base: pwindow

View File

@@ -125,10 +125,12 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 50
acts: [ "Destruction" ] behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: entity - type: entity
id: FoamedIronMetal id: FoamedIronMetal

View File

@@ -164,9 +164,12 @@
200: !type:DeadMobState {} 200: !type:DeadMobState {}
- type: Destructible - type: Destructible
thresholds: thresholds:
400: - trigger:
behaviors: !type:TotalDamageTypesTrigger
- !type:GibBehavior { } damage:
Blunt: 400
behaviors:
- !type:GibBehavior { }
- type: HeatResistance - type: HeatResistance
- type: Appearance - type: Appearance
visuals: visuals:

View File

@@ -26,18 +26,20 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
5: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundCollectionBehavior damage: 5
soundCollection: GlassBreak behaviors:
- !type:SpillBehavior { } - !type:PlaySoundCollectionBehavior
- !type:SpawnEntitiesBehavior soundCollection: GlassBreak
spawn: - !type:SpillBehavior { }
ShardGlass: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 ShardGlass:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: DamageOnLand - type: DamageOnLand
amount: 5 amount: 5
- type: DamageOtherOnHit - type: DamageOtherOnHit

View File

@@ -19,18 +19,20 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
5: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundCollectionBehavior damage: 5
soundCollection: GlassBreak behaviors:
- !type:SpillBehavior { } - !type:PlaySoundCollectionBehavior
- !type:SpawnEntitiesBehavior soundCollection: GlassBreak
spawn: - !type:SpillBehavior { }
ShardGlass: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 2 ShardGlass:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 2
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: entity - type: entity
parent: DrinkBottleBaseFull parent: DrinkBottleBaseFull

View File

@@ -131,17 +131,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
10: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 10
sound: /Audio/Effects/glass_break1.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/glass_break1.ogg
FloodlightBroken: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 FloodlightBroken:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Appearance - type: Appearance
visuals: visuals:
- type: FlashLightVisualizer - type: FlashLightVisualizer
@@ -160,17 +162,19 @@
resistances: metallicResistances resistances: metallicResistances
- type: Destructible - type: Destructible
thresholds: thresholds:
20: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundBehavior damage: 20
sound: /Audio/Effects/metalbreak.ogg behaviors:
- !type:SpawnEntitiesBehavior - !type:PlaySoundBehavior
spawn: sound: /Audio/Effects/metalbreak.ogg
SteelSheet1: - !type:SpawnEntitiesBehavior
min: 1 spawn:
max: 1 SteelSheet1:
- !type:DoActsBehavior min: 1
acts: [ "Destruction" ] max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Physics - type: Physics
shapes: shapes:
- !type:PhysShapeAabb - !type:PhysShapeAabb

View File

@@ -11,23 +11,27 @@
amount: 5 amount: 5
- type: Destructible - type: Destructible
thresholds: thresholds:
5: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:PlaySoundCollectionBehavior damage: 5
soundCollection: GlassBreak behaviors:
- !type:DoActsBehavior - !type:PlaySoundCollectionBehavior
acts: [ "Breakage" ] soundCollection: GlassBreak
10: - !type:DoActsBehavior
behaviors: acts: [ "Breakage" ]
- !type:PlaySoundCollectionBehavior - trigger:
soundCollection: GlassBreak !type:TotalDamageTrigger
- !type:SpawnEntitiesBehavior damage: 10
spawn: behaviors:
ShardGlass: - !type:PlaySoundCollectionBehavior
min: 1 soundCollection: GlassBreak
max: 1 - !type:SpawnEntitiesBehavior
- !type:DoActsBehavior spawn:
acts: [ "Destruction" ] ShardGlass:
min: 1
max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: entity - type: entity
parent: BaseLightbulb parent: BaseLightbulb

View File

@@ -25,10 +25,12 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
10: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 10
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Appearance - type: Appearance
visuals: visuals:
- type: TimerTriggerVisualizer - type: TimerTriggerVisualizer
@@ -57,10 +59,12 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
10: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 10
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Appearance - type: Appearance
visuals: visuals:
- type: TimerTriggerVisualizer - type: TimerTriggerVisualizer
@@ -89,10 +93,12 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
10: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 10
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Appearance - type: Appearance
visuals: visuals:
- type: TimerTriggerVisualizer - type: TimerTriggerVisualizer
@@ -120,10 +126,12 @@
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholds: thresholds:
50: - trigger:
behaviors: !type:TotalDamageTrigger
- !type:DoActsBehavior damage: 50
acts: ["Destruction"] behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- type: Appearance - type: Appearance
visuals: visuals:
- type: TimerTriggerVisualizer - type: TimerTriggerVisualizer