diff --git a/Content.Server/Clothing/Components/GloveHeatResistanceComponent.cs b/Content.Server/Clothing/Components/GloveHeatResistanceComponent.cs deleted file mode 100644 index 29a3b901a786..000000000000 --- a/Content.Server/Clothing/Components/GloveHeatResistanceComponent.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Content.Server.Clothing.Components; - -/// -/// TODO this needs removed somehow. -/// Handles 'heat resistance' for gloves touching bulbs and that's it, ick. -/// -[RegisterComponent] -public sealed partial class GloveHeatResistanceComponent : Component -{ - [DataField("heatResistance")] - public int HeatResistance = 323; -} diff --git a/Content.Server/Light/Components/PoweredLightComponent.cs b/Content.Server/Light/Components/PoweredLightComponent.cs index 489a49eec220..1a6f610516e8 100644 --- a/Content.Server/Light/Components/PoweredLightComponent.cs +++ b/Content.Server/Light/Components/PoweredLightComponent.cs @@ -30,10 +30,6 @@ public sealed partial class PoweredLightComponent : Component [DataField("on")] public bool On = true; - [DataField("damage", required: true)] - [ViewVariables(VVAccess.ReadWrite)] - public DamageSpecifier Damage = default!; - [DataField("ignoreGhostsBoo")] public bool IgnoreGhostsBoo; diff --git a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs index 8aa432c21ea2..33b7ce0782f4 100644 --- a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs +++ b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs @@ -1,5 +1,4 @@ using Content.Server.Administration.Logs; -using Content.Server.Clothing.Components; using Content.Server.DeviceLinking.Events; using Content.Server.DeviceLinking.Systems; using Content.Server.DeviceNetwork; @@ -24,6 +23,8 @@ using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.Shared.Audio.Systems; +using Content.Shared.Damage.Systems; +using Content.Shared.Damage.Components; namespace Content.Server.Light.EntitySystems { @@ -33,11 +34,8 @@ namespace Content.Server.Light.EntitySystems public sealed class PoweredLightSystem : EntitySystem { [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly SharedAmbientSoundSystem _ambientSystem = default!; [Dependency] private readonly LightBulbSystem _bulbSystem = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - [Dependency] private readonly IAdminLogManager _adminLogger= default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly DeviceLinkSystem _signalSystem = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; @@ -45,7 +43,7 @@ public sealed class PoweredLightSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly PointLightSystem _pointLight = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly DamageOnInteractSystem _damageOnInteractSystem = default!; private static readonly TimeSpan ThunkDelay = TimeSpan.FromSeconds(2); public const string LightBulbContainer = "light_bulb"; @@ -106,40 +104,7 @@ private void OnInteractHand(EntityUid uid, PoweredLightComponent light, Interact if (bulbUid == null) return; - // check if it's possible to apply burn damage to user var userUid = args.User; - if (EntityManager.TryGetComponent(bulbUid.Value, out LightBulbComponent? lightBulb)) - { - // get users heat resistance - var res = int.MinValue; - if (_inventory.TryGetSlotEntity(userUid, "gloves", out var slotEntity) && - TryComp(slotEntity, out var gloves)) - { - res = gloves.HeatResistance; - } - - // check heat resistance against user - var burnedHand = light.CurrentLit && res < lightBulb.BurningTemperature; - if (burnedHand) - { - var damage = _damageableSystem.TryChangeDamage(userUid, light.Damage, origin: userUid); - - // If damage is null then the entity could not take heat damage so they did not get burned. - if (damage != null) - { - - var burnMsg = Loc.GetString("powered-light-component-burn-hand"); - _popupSystem.PopupEntity(burnMsg, uid, userUid); - _adminLogger.Add(LogType.Damaged, $"{ToPrettyString(args.User):user} burned their hand on {ToPrettyString(args.Target):target} and received {damage.GetTotal():damage} damage"); - _audio.PlayEntity(light.BurnHandSound, Filter.Pvs(uid), uid, true); - - args.Handled = true; - return; - } - } - } - - //removing a broken/burned bulb, so allow instant removal if(TryComp(bulbUid.Value, out var bulb) && bulb.State != LightBulbState.Normal) { @@ -435,6 +400,10 @@ private void SetLight(EntityUid uid, bool value, Color? color = null, PoweredLig if (softness != null) _pointLight.SetSoftness(uid, (float) softness, pointLight); } + + // light bulbs burn your hands! + if (TryComp(uid, out var damageOnInteractComp)) + _damageOnInteractSystem.SetIsDamageActiveTo((uid, damageOnInteractComp), value); } public void ToggleLight(EntityUid uid, PoweredLightComponent? light = null) diff --git a/Content.Shared/Anomaly/Components/AnomalyComponent.cs b/Content.Shared/Anomaly/Components/AnomalyComponent.cs index 88e942ec5079..724dfd38d2f6 100644 --- a/Content.Shared/Anomaly/Components/AnomalyComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalyComponent.cs @@ -202,20 +202,6 @@ public sealed partial class AnomalyComponent : Component public float GrowingPointMultiplier = 1.5f; #endregion - /// - /// The amount of damage dealt when either a player touches the anomaly - /// directly or by hitting the anomaly. - /// - [DataField(required: true)] - public DamageSpecifier AnomalyContactDamage = default!; - - /// - /// The sound effect played when a player - /// burns themselves on an anomaly via contact. - /// - [DataField] - public SoundSpecifier AnomalyContactDamageSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); - /// /// A prototype entity that appears when an anomaly supercrit collapse. /// diff --git a/Content.Shared/Anomaly/SharedAnomalySystem.cs b/Content.Shared/Anomaly/SharedAnomalySystem.cs index da1d31c6ff65..c3d6591b7252 100644 --- a/Content.Shared/Anomaly/SharedAnomalySystem.cs +++ b/Content.Shared/Anomaly/SharedAnomalySystem.cs @@ -30,7 +30,6 @@ public abstract class SharedAnomalySystem : EntitySystem [Dependency] private readonly INetManager _net = default!; [Dependency] protected readonly IRobustRandom Random = default!; [Dependency] protected readonly ISharedAdminLogManager AdminLog = default!; - [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] protected readonly SharedAudioSystem Audio = default!; [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; @@ -42,26 +41,10 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnInteractHand); - SubscribeLocalEvent(OnAttacked); SubscribeLocalEvent(OnAnomalyThrowStart); SubscribeLocalEvent(OnAnomalyThrowEnd); } - private void OnInteractHand(EntityUid uid, AnomalyComponent component, InteractHandEvent args) - { - DoAnomalyBurnDamage(uid, args.User, component); - args.Handled = true; - } - - private void OnAttacked(EntityUid uid, AnomalyComponent component, AttackedEvent args) - { - if (HasComp(args.Used)) - return; - - DoAnomalyBurnDamage(uid, args.User, component); - } - private void OnAnomalyThrowStart(Entity ent, ref MeleeThrowOnHitStartEvent args) { if (!TryComp(args.Used, out var corePowered) || !TryComp(ent, out var body)) @@ -75,15 +58,6 @@ private void OnAnomalyThrowEnd(Entity ent, ref MeleeThrowOnHit _physics.SetBodyType(ent, BodyType.Static); } - public void DoAnomalyBurnDamage(EntityUid source, EntityUid target, AnomalyComponent component) - { - _damageable.TryChangeDamage(target, component.AnomalyContactDamage, true); - if (!Timing.IsFirstTimePredicted || _net.IsServer) - return; - Audio.PlayPvs(component.AnomalyContactDamageSound, source); - Popup.PopupEntity(Loc.GetString("anomaly-component-contact-damage"), target, target); - } - public void DoAnomalyPulse(EntityUid uid, AnomalyComponent? component = null) { if (!Resolve(uid, ref component)) diff --git a/Content.Shared/Damage/Components/DamageOnAttackedComponent.cs b/Content.Shared/Damage/Components/DamageOnAttackedComponent.cs new file mode 100644 index 000000000000..5f6bd7d99720 --- /dev/null +++ b/Content.Shared/Damage/Components/DamageOnAttackedComponent.cs @@ -0,0 +1,47 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Damage.Components; + + +/// +/// This component is added to entities that you want to damage the player +/// if the player interacts with it. For example, if a player tries touching +/// a hot light bulb or an anomaly. This damage can be cancelled if the user +/// has a component that protects them from this. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class DamageOnAttackedComponent : Component +{ + /// + /// How much damage to apply to the person making contact + /// + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier Damage = default!; + + /// + /// Whether the damage should be resisted by a person's armor values + /// and the + /// + [DataField] + public bool IgnoreResistances = false; + + /// + /// What kind of localized text should pop up when they interact with the entity + /// + [DataField] + public LocId? PopupText; + + /// + /// The sound that should be made when interacting with the entity + /// + [DataField] + public SoundSpecifier InteractSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); + + /// + /// Generic boolean to toggle the damage application on and off + /// This is useful for things that can be toggled on or off, like a stovetop + /// + [DataField, AutoNetworkedField] + public bool IsDamageActive = true; +} diff --git a/Content.Shared/Damage/Components/DamageOnAttackedProtectionComponent.cs b/Content.Shared/Damage/Components/DamageOnAttackedProtectionComponent.cs new file mode 100644 index 000000000000..9581d2049664 --- /dev/null +++ b/Content.Shared/Damage/Components/DamageOnAttackedProtectionComponent.cs @@ -0,0 +1,29 @@ +using Content.Shared.Inventory; +using Robust.Shared.GameStates; + +namespace Content.Shared.Damage.Components; + + +/// +/// This component is added to entities to protect them from being damaged +/// when attacking objects with the +/// If the entity has sufficient protection, the entity will take no damage. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class DamageOnAttackedProtectionComponent : Component, IClothingSlots +{ + /// + /// How much and what kind of damage to protect the user from + /// when interacting with something with + /// + [DataField(required: true)] + public DamageModifierSet DamageProtection = default!; + + /// + /// Only protects if the item is in the correct slot + /// i.e. having gloves in your pocket doesn't protect you, it has to be on your hands + /// Set slots to NONE if it works while you hold the item in your main hand + /// + [DataField] + public SlotFlags Slots { get; set; } = SlotFlags.WITHOUT_POCKET; +} diff --git a/Content.Shared/Damage/Components/DamageOnInteractComponent.cs b/Content.Shared/Damage/Components/DamageOnInteractComponent.cs new file mode 100644 index 000000000000..9487dec8ef96 --- /dev/null +++ b/Content.Shared/Damage/Components/DamageOnInteractComponent.cs @@ -0,0 +1,47 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Damage.Components; + + +/// +/// This component is added to entities that you want to damage the player +/// if the player interacts with it. For example, if a player tries touching +/// a hot light bulb or an anomaly. This damage can be cancelled if the user +/// has a component that protects them from this. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class DamageOnInteractComponent : Component +{ + /// + /// How much damage to apply to the person making contact + /// + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier Damage = default!; + + /// + /// Whether the damage should be resisted by a person's armor values + /// and the + /// + [DataField] + public bool IgnoreResistances; + + /// + /// What kind of localized text should pop up when they interact with the entity + /// + [DataField] + public LocId? PopupText; + + /// + /// The sound that should be made when interacting with the entity + /// + [DataField] + public SoundSpecifier InteractSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); + + /// + /// Generic boolean to toggle the damage application on and off + /// This is useful for things that can be toggled on or off, like a stovetop + /// + [DataField, AutoNetworkedField] + public bool IsDamageActive = true; +} diff --git a/Content.Shared/Damage/Components/DamageOnInteractProtectionComponent.cs b/Content.Shared/Damage/Components/DamageOnInteractProtectionComponent.cs new file mode 100644 index 000000000000..f57c3d22c17c --- /dev/null +++ b/Content.Shared/Damage/Components/DamageOnInteractProtectionComponent.cs @@ -0,0 +1,29 @@ +using Content.Shared.Inventory; +using Robust.Shared.GameStates; + +namespace Content.Shared.Damage.Components; + + +/// +/// This component is added to entities to protect them from being damaged +/// when interacting with objects with the +/// If the entity has sufficient protection, interaction with the object is not cancelled. +/// This allows the user to do things like remove a lightbulb. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class DamageOnInteractProtectionComponent : Component, IClothingSlots +{ + /// + /// How much and what kind of damage to protect the user from + /// when interacting with something with + /// + [DataField(required: true)] + public DamageModifierSet DamageProtection = default!; + + /// + /// Only protects if the item is in the correct slot + /// i.e. having gloves in your pocket doesn't protect you, it has to be on your hands + /// + [DataField] + public SlotFlags Slots { get; set; } = SlotFlags.GLOVES; +} diff --git a/Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs b/Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs new file mode 100644 index 000000000000..ab5866c5aa57 --- /dev/null +++ b/Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs @@ -0,0 +1,99 @@ +using Content.Shared.Administration.Logs; +using Content.Shared.Damage.Components; +using Content.Shared.Database; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Inventory; +using Content.Shared.Popups; +using Content.Shared.Weapons.Melee.Events; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; +using Robust.Shared.Timing; + +namespace Content.Shared.Damage.Systems; + +public sealed class DamageOnAttackedSystem : EntitySystem +{ + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAttacked); + } + + /// + /// Damages the user that attacks the entity and potentially + /// plays a sound or pops up text in response + /// + /// The entity being hit + /// Contains the user that hit the entity + private void OnAttacked(Entity entity, ref AttackedEvent args) + { + if (!entity.Comp.IsDamageActive) + return; + + var totalDamage = entity.Comp.Damage; + + if (!entity.Comp.IgnoreResistances) + { + // try to get the damage on attacked protection component from something the entity has in their inventory + _inventorySystem.TryGetInventoryEntity(args.User, out var protectiveEntity); + + // if comp is null that means the user didn't have anything equipped that protected them + // let's check their hands to see if the thing they attacked with gives them protection, like the GORILLA gauntlet + if (protectiveEntity.Comp == null && TryComp(args.User, out var handsComp)) + { + if (_handsSystem.TryGetActiveItem((args.User, handsComp), out var itemInHand) && + TryComp(itemInHand, out var itemProtectComp) + && itemProtectComp.Slots == SlotFlags.NONE) + { + protectiveEntity = (itemInHand.Value, itemProtectComp); + } + } + + // if comp is null, that means both the inventory and hands had nothing to protect them + // let's check if the entity itself has the protective comp, like with borgs + if (protectiveEntity.Comp == null && + TryComp(args.User, out var protectiveComp)) + { + protectiveEntity = (args.User, protectiveComp); + } + + // if comp is NOT NULL that means they have damage protection! + if (protectiveEntity.Comp != null) + { + totalDamage = DamageSpecifier.ApplyModifierSet(totalDamage, protectiveEntity.Comp.DamageProtection); + } + } + + totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, entity.Comp.IgnoreResistances, origin: entity); + + if (totalDamage != null && totalDamage.AnyPositive()) + { + _adminLogger.Add(LogType.Damaged, $"{ToPrettyString(args.User):user} injured themselves by attacking {ToPrettyString(entity):target} and received {totalDamage.GetTotal():damage} damage"); + _audioSystem.PlayPredicted(entity.Comp.InteractSound, entity, args.User); + + if (entity.Comp.PopupText != null) + _popupSystem.PopupClient(Loc.GetString(entity.Comp.PopupText), args.User, args.User); + + } + } + + public void SetIsDamageActiveTo(Entity entity, bool mode) + { + if (entity.Comp.IsDamageActive == mode) + return; + + entity.Comp.IsDamageActive = mode; + Dirty(entity); + } +} diff --git a/Content.Shared/Damage/Systems/DamageOnInteractSystem.cs b/Content.Shared/Damage/Systems/DamageOnInteractSystem.cs new file mode 100644 index 000000000000..4b50a1fd0e07 --- /dev/null +++ b/Content.Shared/Damage/Systems/DamageOnInteractSystem.cs @@ -0,0 +1,85 @@ +using Content.Shared.Administration.Logs; +using Content.Shared.Damage.Components; +using Content.Shared.Database; +using Content.Shared.Interaction; +using Content.Shared.Inventory; +using Content.Shared.Popups; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; +using Robust.Shared.Timing; + +namespace Content.Shared.Damage.Systems; + +public sealed class DamageOnInteractSystem : EntitySystem +{ + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnHandInteract); + } + + /// + /// Damages the user that interacts with the entity with an empty hand and + /// plays a sound or pops up text in response. If the user does not have + /// proper protection, the user will only be damaged and other interactions + /// will be cancelled. + /// + /// The entity being interacted with + /// Contains the user that interacted with the entity + private void OnHandInteract(Entity entity, ref InteractHandEvent args) + { + if (!entity.Comp.IsDamageActive) + return; + + var totalDamage = entity.Comp.Damage; + + if (!entity.Comp.IgnoreResistances) + { + // try to get damage on interact protection from either the inventory slots of the entity + _inventorySystem.TryGetInventoryEntity(args.User, out var protectiveEntity); + + // or checking the entity for the comp itself if the inventory didn't work + if (protectiveEntity.Comp == null && TryComp(args.User, out var protectiveComp)) + { + protectiveEntity = (args.User, protectiveComp); + } + + // if protectiveComp isn't null after all that, it means the user has protection, + // so let's calculate how much they resist + if (protectiveEntity.Comp != null) + { + totalDamage = DamageSpecifier.ApplyModifierSet(totalDamage, protectiveEntity.Comp.DamageProtection); + } + } + + totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, origin: args.Target); + + if (totalDamage != null && totalDamage.AnyPositive()) + { + args.Handled = true; + _adminLogger.Add(LogType.Damaged, $"{ToPrettyString(args.User):user} injured their hand by interacting with {ToPrettyString(args.Target):target} and received {totalDamage.GetTotal():damage} damage"); + _audioSystem.PlayPredicted(entity.Comp.InteractSound, args.Target, args.User); + + if (entity.Comp.PopupText != null) + _popupSystem.PopupClient(Loc.GetString(entity.Comp.PopupText), args.User, args.User); + } + } + + public void SetIsDamageActiveTo(Entity entity, bool mode) + { + if (entity.Comp.IsDamageActive == mode) + return; + + entity.Comp.IsDamageActive = mode; + Dirty(entity); + } +} diff --git a/Content.Shared/Inventory/InventorySystem.Slots.cs b/Content.Shared/Inventory/InventorySystem.Slots.cs index 228b788722ec..2522dd5d0a33 100644 --- a/Content.Shared/Inventory/InventorySystem.Slots.cs +++ b/Content.Shared/Inventory/InventorySystem.Slots.cs @@ -30,7 +30,7 @@ private void ShutdownSlots() /// /// Tries to find an entity in the specified slot with the specified component. /// - public bool TryGetInventoryEntity(Entity entity, out EntityUid targetUid) + public bool TryGetInventoryEntity(Entity entity, out Entity target) where T : IComponent, IClothingSlots { if (TryGetContainerSlotEnumerator(entity.Owner, out var containerSlotEnumerator)) @@ -43,12 +43,12 @@ public bool TryGetInventoryEntity(Entity entity, out Ent if ((((IClothingSlots) required).Slots & slot.SlotFlags) == 0x0) continue; - targetUid = item; + target = (item, required); return true; } } - targetUid = EntityUid.Invalid; + target = EntityUid.Invalid; return false; } diff --git a/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml b/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml index 02cf0ab6f67d..c1a53ccf6e5f 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml @@ -23,6 +23,10 @@ tags: - ClothMade - WhitelistChameleon + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 5 # the average lightbulb only does around four damage! - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Clothing/Hands/colored.yml b/Resources/Prototypes/Entities/Clothing/Hands/colored.yml index 0fa298b648bd..556442cee118 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/colored.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/colored.yml @@ -283,8 +283,6 @@ color: "#535353" - type: Clothing sprite: Clothing/Hands/Gloves/Color/black.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Butcherable butcheringType: Knife spawned: @@ -305,8 +303,6 @@ sprite: Clothing/Hands/Gloves/Color/yellow.rsi - type: Clothing sprite: Clothing/Hands/Gloves/Color/yellow.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Butcherable butcheringType: Knife spawned: @@ -323,9 +319,6 @@ name: budget insulated gloves description: These gloves are cheap knockoffs of the coveted ones - no way this can end badly. components: - - type: GloveHeatResistance - # can't take out lights using budgets - heatResistance: 0 - type: RandomInsulation # Why repeated numbers? So some numbers are more common, of course! list: diff --git a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml index f1d99884658a..53a165cd5716 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml @@ -103,8 +103,6 @@ sprite: Clothing/Hands/Gloves/captain.rsi - type: Clothing sprite: Clothing/Hands/Gloves/captain.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Insulated - type: Fiber fiberMaterial: fibers-durathread @@ -169,8 +167,6 @@ sprite: Clothing/Hands/Gloves/leather.rsi - type: Clothing sprite: Clothing/Hands/Gloves/leather.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Fiber fiberMaterial: fibers-leather fiberColor: fibers-brown @@ -225,8 +221,6 @@ enum.ToggleVisuals.Layer: True: {state: icon-green} False: {state: icon} - - type: GloveHeatResistance - heatResistance: 1400 - type: Insulated - type: Fiber fiberMaterial: fibers-nanomachines @@ -270,8 +264,6 @@ sprite: Clothing/Hands/Gloves/combat.rsi - type: Clothing sprite: Clothing/Hands/Gloves/combat.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Insulated - type: Fiber fiberMaterial: fibers-insulative @@ -287,8 +279,6 @@ sprite: Clothing/Hands/Gloves/tacticalmaidgloves.rsi - type: Clothing sprite: Clothing/Hands/Gloves/tacticalmaidgloves.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Insulated - type: Fiber fiberColor: fibers-black @@ -324,6 +314,10 @@ - type: Fiber fiberMaterial: fibers-synthetic fiberColor: fibers-black + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 0 # no protection - type: entity parent: ClothingHandsBase @@ -338,6 +332,10 @@ - type: Fiber fiberMaterial: fibers-insulative fiberColor: fibers-yellow + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 0 # no protection - type: entity parent: ClothingHandsButcherable @@ -352,6 +350,10 @@ - type: Fiber fiberMaterial: fibers-insulative fiberColor: fibers-olive + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 0 # no protection - type: entity # Intentionally named after regular gloves, they're meant to be sneaky. diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml index 7c264a596a0c..5df6adffec96 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml @@ -136,6 +136,11 @@ - WhitelistChameleon - type: ClothingRequiredStepTriggerImmune slots: WITHOUT_POCKET + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 10 # the average lightbulb only does around four damage! + slots: OUTERCLOTHING - type: entity abstract: true @@ -156,6 +161,11 @@ size: Huge - type: ClothingRequiredStepTriggerImmune slots: WITHOUT_POCKET + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 10 # the average lightbulb only does around four damage! + slots: OUTERCLOTHING - type: entity parent: ClothingOuterBase diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 2618207b7a90..6c73fd8f1167 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -222,6 +222,10 @@ guides: - Cyborgs - type: StepTriggerImmune + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 10 # capable of touching light bulbs and stoves without feeling pain! - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml b/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml index 6f9935d351d3..1db787a66d84 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml @@ -110,9 +110,6 @@ collection: BananiumHorn params: volume: 5 - anomalyContactDamage: - types: - Radiation: 10 - type: Input context: "human" - type: Bloodstream @@ -158,9 +155,6 @@ suffix: "Ice" components: - type: Anomaly - anomalyContactDamage: - types: - Cold: 10 - type: ExplosionAnomaly supercriticalExplosion: Cryo explosionTotalIntensity: 1000 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml index 99f874406b42..929f509710ec 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml @@ -147,3 +147,10 @@ - type: ContainerContainer containers: core_slot: !type:ContainerSlot + - type: DamageOnAttackedProtection + damageProtection: + flatReductions: + Heat: 100 + Cold: 100 + Radiation: 100 + slots: NONE diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml index 0bab2c828dec..838cde619faf 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml @@ -154,7 +154,7 @@ - type: DisarmMalus - type: entity - name: The Throngler + name: Throngler parent: BaseSword id: Throngler description: Why would you make this? @@ -180,3 +180,6 @@ size: Ginormous sprite: Objects/Weapons/Melee/Throngler-in-hand.rsi - type: DisarmMalus + - type: Grammar + attributes: + proper: true diff --git a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml index 436eaa2697f0..f684ca3425a3 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml @@ -89,9 +89,6 @@ enabled: false - type: PoweredLight bulb: Tube - damage: - types: - Heat: 2 - type: ContainerContainer containers: light_bulb: !type:ContainerSlot @@ -117,6 +114,11 @@ on: base broken: broken burned: burned + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: Poweredlight @@ -130,15 +132,17 @@ enabled: true - type: PoweredLight hasLampOnSpawn: LightTube - damage: - types: - Heat: 2 - type: AmbientOnPowered - type: AmbientSound volume: -15 range: 2 sound: path: /Audio/Ambience/Objects/light_hum.ogg + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand #LED lights - type: entity @@ -149,14 +153,16 @@ components: - type: PoweredLight hasLampOnSpawn: LedLightTube - damage: - types: - Heat: 1 #LEDs don't get as hot - type: PointLight radius: 15 energy: 1 softness: 0.9 color: "#EEEEFF" + - type: DamageOnInteract + damage: + types: + Heat: 1 # LEDs don't get as hot + popupText: powered-light-component-burn-hand - type: entity parent: AlwaysPoweredWallLight @@ -178,9 +184,11 @@ components: - type: PoweredLight hasLampOnSpawn: ExteriorLightTube + - type: DamageOnInteract damage: types: - Heat: 4 #brighter light gets hotter + Heat: 4 # brighter light gets hotter + popupText: powered-light-component-burn-hand - type: entity parent: AlwaysPoweredWallLight @@ -202,14 +210,16 @@ components: - type: PoweredLight hasLampOnSpawn: SodiumLightTube - damage: - types: - Heat: 2 - type: PointLight radius: 10 energy: 2.5 softness: 0.9 color: "#FFAF38" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity parent: AlwaysPoweredWallLight @@ -289,9 +299,6 @@ light_bulb: !type:ContainerSlot - type: PoweredLight bulb: Bulb - damage: - types: - Heat: 2 - type: ApcPowerReceiver - type: ExtensionCableReceiver - type: DeviceNetwork @@ -312,6 +319,11 @@ - On - Off - Toggle + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: PoweredLEDSmallLight @@ -328,9 +340,11 @@ color: "#EEEEFF" - type: PoweredLight hasLampOnSpawn: LedLightBulb + - type: DamageOnInteract damage: types: Heat: 1 + popupText: powered-light-component-burn-hand - type: entity id: PoweredSmallLight @@ -343,9 +357,11 @@ enabled: true - type: PoweredLight hasLampOnSpawn: LightBulb + - type: DamageOnInteract damage: types: Heat: 2 + popupText: powered-light-component-burn-hand #Emergency Lights - type: entity @@ -398,14 +414,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalCyan - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#47f8ff" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightCyan @@ -425,14 +443,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalBlue - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#39a1ff" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightBlue @@ -452,14 +472,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalPink - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#ff66cc" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightPink @@ -479,14 +501,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalOrange - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#ff8227" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightOrange @@ -506,14 +530,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalRed - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#fb4747" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightRed @@ -533,14 +559,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalGreen - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#52ff39" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightGreen diff --git a/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml index 2afde4ef3fce..0771cb71bc06 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml @@ -77,9 +77,6 @@ enabled: false - type: PoweredLight bulb: Tube - damage: - types: - Heat: 2 - type: ContainerContainer containers: light_bulb: !type:ContainerSlot @@ -108,6 +105,11 @@ on: base broken: broken burned: burned + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: PoweredLightPostSmall @@ -122,9 +124,6 @@ enabled: true - type: PoweredLight hasLampOnSpawn: LightTube - damage: - types: - Heat: 2 - type: StaticPrice price: 25 - type: AmbientOnPowered @@ -133,6 +132,11 @@ range: 3 sound: path: /Audio/Ambience/Objects/light_hum.ogg + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: PoweredLEDLightPostSmall @@ -151,9 +155,6 @@ color: "#EEEEFF" - type: PoweredLight hasLampOnSpawn: LedLightTube - damage: - types: - Heat: 1 - type: StaticPrice price: 25 - type: AmbientOnPowered @@ -162,3 +163,8 @@ range: 3 sound: path: /Audio/Ambience/Objects/light_hum.ogg + - type: DamageOnInteract + damage: + types: + Heat: 1 + popupText: powered-light-component-burn-hand diff --git a/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml index 72f543964699..50e24eab73d2 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml @@ -87,9 +87,6 @@ - type: PoweredLight bulb: Bulb on: false - damage: - types: - Heat: 2 - type: ApcPowerReceiver - type: ExtensionCableReceiver - type: DeviceNetwork @@ -113,6 +110,11 @@ - type: Construction graph: LightFixture node: strobeLight + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: PoweredStrobeLightPolice diff --git a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml index 8bca49c4e5fe..a16aaaabbbe3 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml @@ -9,9 +9,6 @@ collection: RadiationPulse params: volume: 5 - anomalyContactDamage: - types: - Radiation: 10 - type: AmbientSound range: 5 volume: -5 @@ -51,6 +48,15 @@ - type: SecretDataAnomaly randomStartSecretMin: 0 randomStartSecretMax: 2 + - type: DamageOnInteract + damage: + types: + Radiation: 10 + popupText: anomaly-component-contact-damage + - type: DamageOnAttacked + damage: + types: + Radiation: 10 - type: entity id: AnomalyPyroclastic @@ -99,6 +105,15 @@ - type: IgniteOnCollide fixtureId: fix1 fireStacks: 1 + - type: DamageOnInteract + damage: + types: + Heat: 10 + popupText: anomaly-component-contact-damage + - type: DamageOnAttacked + damage: + types: + Heat: 10 - type: entity id: AnomalyGravity @@ -294,9 +309,6 @@ collection: RadiationPulse params: volume: 5 - anomalyContactDamage: - types: - Radiation: 10 - type: entity id: AnomalyIce @@ -319,9 +331,6 @@ - type: Anomaly corePrototype: AnomalyCoreIce coreInertPrototype: AnomalyCoreIceInert - anomalyContactDamage: - types: - Cold: 10 - type: ExplosionAnomaly supercriticalExplosion: Cryo explosionTotalIntensity: 300 @@ -345,6 +354,15 @@ releasedGas: 8 # Frezon. Please replace if there is a better way to specify this releaseOnMaxSeverity: true spawnRadius: 0 + - type: DamageOnInteract + damage: + types: + Cold: 10 + popupText: anomaly-component-contact-damage + - type: DamageOnAttacked + damage: + types: + Cold: 10 - type: entity id: AnomalyRockBase @@ -609,9 +627,6 @@ coreInertPrototype: AnomalyCoreFloraInert minPulseLength: 60 maxPulseLength: 120 - anomalyContactDamage: - types: - Slash: 0 - type: TileSpawnAnomaly entries: - settings: @@ -715,9 +730,6 @@ coreInertPrototype: AnomalyCoreLiquidInert minPulseLength: 60 maxPulseLength: 120 - anomalyContactDamage: - types: - Slash: 1 - type: EntitySpawnAnomaly entries: - settings: @@ -829,9 +841,6 @@ coreInertPrototype: AnomalyCoreShadowInert minPulseLength: 60 maxPulseLength: 120 - anomalyContactDamage: - types: - Cold: 10 animationTime: 4 offset: "-0.1,0.1" - type: EntitySpawnAnomaly @@ -857,3 +866,12 @@ - type: Tag tags: - SpookyFog + - type: DamageOnInteract + damage: + types: + Cold: 10 + popupText: anomaly-component-contact-damage + - type: DamageOnAttacked + damage: + types: + Cold: 10 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/service_light.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/service_light.yml index b8aaa60c3723..baadcb67dbf8 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/service_light.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/service_light.yml @@ -24,6 +24,8 @@ bulb: Bulb on: false hasLampOnSpawn: ServiceLightBulb + - type: DamageOnInteract damage: types: Heat: 5 + popupText: powered-light-component-burn-hand