Files
tbd-station-14/Content.Server/GameObjects/Components/Destructible/Threshold.cs
DrSmugleaf 02bca4c0d8 Damage rework (#2525)
* Make damage work through messages and events, make destructible not inherit ruinable or reference damageable

* Copy sound logic to destructible component for now

* Fix typo

* Fix prototype error

* Remove breakable component damageable reference

* Remove breakable construction reference

* Remove ruinable component

* Move thresholds to individual components and away from damageable

* Add threshold property to damageable component code

* Add thresholds to destructible component, add states to damageable, remove damage container, fix up mob states

* Being alive isn't normal

* Fix not reading the id

* Merge fixes

* YAML fixes

* Grammar moment

* Remove unnecessary dependency

* Update thresholds doc

* Change naming of thresholds to states in MobStateComponent

* Being alive is once again normal

* Make DamageState a byte

* Bring out classes structs and enums from DestructibleComponent

* Add test for destructible thresholds

* Merge fixes

* More merge fixes and fix rejuvenate test

* Remove IMobState.IsConscious

* More merge fixes someone please god review this shit already

* Fix rejuvenate test

* Update outdated destructible in YAML

* Fix repeatedly entering the current state

* Fix repeatedly entering the current state, add Threshold.TriggersOnce and expand test

* Update saltern
2020-12-07 14:52:55 +01:00

149 lines
5.1 KiB
C#

#nullable enable
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Stack;
using Content.Shared.Audio;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Utility;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Random;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Destructible
{
public class Threshold : IExposeData
{
/// <summary>
/// Entities spawned on reaching this threshold, from a min to a max.
/// </summary>
[ViewVariables] public Dictionary<string, MinMax>? Spawn;
/// <summary>
/// Sound played upon destruction.
/// </summary>
[ViewVariables] public string Sound = string.Empty;
/// <summary>
/// Used instead of <see cref="Sound"/> if specified.
/// </summary>
[ViewVariables] public string SoundCollection = string.Empty;
/// <summary>
/// What acts this threshold should trigger upon activation.
/// See <see cref="ActSystem"/>.
/// </summary>
[ViewVariables] public int Acts;
/// <summary>
/// Whether or not this threshold has already been triggered.
/// </summary>
[ViewVariables] public bool Triggered;
/// <summary>
/// Whether or not this threshold only triggers once.
/// If false, it will trigger again once the entity is healed
/// and then damaged to reach this threshold once again.
/// It will not repeatedly trigger as damage rises beyond that.
/// </summary>
[ViewVariables] public bool TriggersOnce;
public void ExposeData(ObjectSerializer serializer)
{
serializer.DataField(ref Spawn, "Spawn", null);
serializer.DataField(ref Sound, "Sound", string.Empty);
serializer.DataField(ref SoundCollection, "SoundCollection", string.Empty);
serializer.DataField(ref Acts, "Acts", 0, WithFormat.Flags<ActsFlags>());
serializer.DataField(ref Triggered, "Triggered", false);
serializer.DataField(ref TriggersOnce, "TriggersOnce", false);
}
/// <summary>
/// Triggers this threshold.
/// </summary>
/// <param name="owner">The entity that owns this threshold.</param>
/// <param name="random">
/// An instance of <see cref="IRobustRandom"/> to get randomness from, if relevant.
/// </param>
/// <param name="actSystem">
/// An instance of <see cref="ActSystem"/> to call acts on, if relevant.
/// </param>
public void Trigger(IEntity owner, IRobustRandom random, ActSystem actSystem)
{
Triggered = true;
PlaySound(owner);
DoSpawn(owner, random);
DoActs(owner, actSystem);
}
private void PlaySound(IEntity owner)
{
var pos = owner.Transform.Coordinates;
var actualSound = string.Empty;
if (SoundCollection != string.Empty)
{
actualSound = AudioHelpers.GetRandomFileFromSoundCollection(SoundCollection);
}
else if (Sound != string.Empty)
{
actualSound = Sound;
}
if (actualSound != string.Empty)
{
EntitySystem.Get<AudioSystem>().PlayAtCoords(actualSound, pos, AudioHelpers.WithVariation(0.125f));
}
}
private void DoSpawn(IEntity owner, IRobustRandom random)
{
if (Spawn == null)
{
return;
}
foreach (var (key, value) in Spawn)
{
var count = value.Min >= value.Max
? value.Min
: random.Next(value.Min, value.Max + 1);
if (count == 0) continue;
if (EntityPrototypeHelpers.HasComponent<StackComponent>(key))
{
var spawned = owner.EntityManager.SpawnEntity(key, owner.Transform.Coordinates);
var stack = spawned.GetComponent<StackComponent>();
stack.Count = count;
spawned.RandomOffset(0.5f);
}
else
{
for (var i = 0; i < count; i++)
{
var spawned = owner.EntityManager.SpawnEntity(key, owner.Transform.Coordinates);
spawned.RandomOffset(0.5f);
}
}
}
}
private void DoActs(IEntity owner, ActSystem acts)
{
if ((Acts & (int) ThresholdActs.Breakage) != 0)
{
acts.HandleBreakage(owner);
}
if ((Acts & (int) ThresholdActs.Destruction) != 0)
{
acts.HandleDestruction(owner);
}
}
}
}