diff --git a/Content.Server/HotPotato/HotPotatoSystem.cs b/Content.Server/HotPotato/HotPotatoSystem.cs index 79be700629..8091eea6fd 100644 --- a/Content.Server/HotPotato/HotPotatoSystem.cs +++ b/Content.Server/HotPotato/HotPotatoSystem.cs @@ -1,4 +1,6 @@ +using Content.Server.Audio; using Content.Server.Explosion.EntitySystems; +using Content.Shared.Damage.Systems; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.HotPotato; @@ -11,6 +13,8 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem { [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly AmbientSoundSystem _ambientSound = default!; + [Dependency] private readonly DamageOnHoldingSystem _damageOnHolding = default!; public override void Initialize() { @@ -23,6 +27,8 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem { EnsureComp(uid); comp.CanTransfer = false; + _ambientSound.SetAmbience(uid, true); + _damageOnHolding.SetEnabled(uid, true); Dirty(comp); } diff --git a/Content.Shared/Damage/Components/DamageOnHoldingComponent.cs b/Content.Shared/Damage/Components/DamageOnHoldingComponent.cs new file mode 100644 index 0000000000..fe28b7e7f0 --- /dev/null +++ b/Content.Shared/Damage/Components/DamageOnHoldingComponent.cs @@ -0,0 +1,33 @@ +using Content.Shared.Damage.Systems; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Damage.Components; + +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState] +[Access(typeof(DamageOnHoldingSystem))] +public sealed partial class DamageOnHoldingComponent : Component +{ + [DataField("enabled"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public bool Enabled = true; + + /// + /// Damage per interval dealt to entity holding the entity with this component + /// + [DataField("damage"), ViewVariables(VVAccess.ReadWrite)] + public DamageSpecifier Damage = new(); + // TODO: make it networked + + /// + /// Delay between damage events in seconds + /// + [DataField("interval"), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public float Interval = 1f; + + [DataField("nextDamage", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] + public TimeSpan NextDamage = TimeSpan.Zero; +} diff --git a/Content.Shared/Damage/Systems/DamageOnHoldingSystem.cs b/Content.Shared/Damage/Systems/DamageOnHoldingSystem.cs new file mode 100644 index 0000000000..e22be2fbbf --- /dev/null +++ b/Content.Shared/Damage/Systems/DamageOnHoldingSystem.cs @@ -0,0 +1,53 @@ +using Content.Shared.Damage.Components; +using Robust.Shared.Containers; +using Robust.Shared.Timing; + +namespace Content.Shared.Damage.Systems; + +public sealed class DamageOnHoldingSystem : EntitySystem +{ + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnUnpaused); + SubscribeLocalEvent(OnMapInit); + } + + public void SetEnabled(EntityUid uid, bool enabled, DamageOnHoldingComponent? component = null) + { + if (Resolve(uid, ref component)) + { + component.Enabled = enabled; + component.NextDamage = _timing.CurTime; + } + } + + private void OnUnpaused(EntityUid uid, DamageOnHoldingComponent component, ref EntityUnpausedEvent args) + { + component.NextDamage += args.PausedTime; + } + + private void OnMapInit(EntityUid uid, DamageOnHoldingComponent component, MapInitEvent args) + { + component.NextDamage = _timing.CurTime; + } + + public override void Update(float frameTime) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var component)) + { + if (!component.Enabled || component.NextDamage > _timing.CurTime) + continue; + if (_container.TryGetContainingContainer(uid, out var container)) + { + _damageableSystem.TryChangeDamage(container.Owner, component.Damage, origin: uid); + } + component.NextDamage = _timing.CurTime + TimeSpan.FromSeconds(component.Interval); + } + } +} \ No newline at end of file diff --git a/Content.Shared/HotPotato/HotPotatoComponent.cs b/Content.Shared/HotPotato/HotPotatoComponent.cs index 2d02e10626..f5b2e16189 100644 --- a/Content.Shared/HotPotato/HotPotatoComponent.cs +++ b/Content.Shared/HotPotato/HotPotatoComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.GameStates; namespace Content.Shared.HotPotato; /// -/// Similar to +/// Similar to /// except entities with this component can be removed in specific case: /// [RegisterComponent, NetworkedComponent] diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml index f7b4d4c5ac..a0f646d1e1 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml @@ -1,6 +1,6 @@ - type: entity name: hot potato - description: Once activated, this time bomb can't be dropped - only passed to someone else! + description: Once activated, you can't drop this time bomb - hit someone else with it to save yourself! Don't burn your hands! parent: BaseItem id: HotPotato components: @@ -11,6 +11,11 @@ - type: Item sprite: Objects/Weapons/Bombs/hot_potato.rsi size: 5 + - type: AmbientSound + enabled: false + range: 8 + sound: + path: /Audio/Effects/lightburn.ogg - type: MeleeWeapon damage: types: @@ -29,6 +34,11 @@ canCreateVacuum: false - type: DeleteOnTrigger - type: HotPotato + - type: DamageOnHolding + enabled: false + damage: + types: + Heat: 1 - type: Appearance visuals: - type: GenericEnumVisualizer