Create Generic DamageOnInteract/Attacked Comps/Systems (#30244)

* Everything but the submodule

* stuff I forgot

* heat

* missed lights

* behonky

* LocId

* I guess it was a skill issue?

* predicted audio

* It works with lights now

* Borg equality

* Gorilla gauntlet grants protection from anomaly returned damage when attacking it

* woops, there we go

* NONE

* Use DamageModifierSets, remove Behonker damage

* Reviews dealt with

---------

Co-authored-by: plykiya <plykiya@protonmail.com>
This commit is contained in:
Plykiya
2024-08-08 22:32:41 -07:00
committed by GitHub
parent 8a4ef69e86
commit b266c9b545
25 changed files with 507 additions and 185 deletions

View File

@@ -1,12 +0,0 @@
namespace Content.Server.Clothing.Components;
/// <summary>
/// TODO this needs removed somehow.
/// Handles 'heat resistance' for gloves touching bulbs and that's it, ick.
/// </summary>
[RegisterComponent]
public sealed partial class GloveHeatResistanceComponent : Component
{
[DataField("heatResistance")]
public int HeatResistance = 323;
}

View File

@@ -30,10 +30,6 @@ namespace Content.Server.Light.Components
[DataField("on")] [DataField("on")]
public bool On = true; public bool On = true;
[DataField("damage", required: true)]
[ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier Damage = default!;
[DataField("ignoreGhostsBoo")] [DataField("ignoreGhostsBoo")]
public bool IgnoreGhostsBoo; public bool IgnoreGhostsBoo;

View File

@@ -1,5 +1,4 @@
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Clothing.Components;
using Content.Server.DeviceLinking.Events; using Content.Server.DeviceLinking.Events;
using Content.Server.DeviceLinking.Systems; using Content.Server.DeviceLinking.Systems;
using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork;
@@ -24,6 +23,8 @@ using Robust.Shared.Containers;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Audio.Systems; using Robust.Shared.Audio.Systems;
using Content.Shared.Damage.Systems;
using Content.Shared.Damage.Components;
namespace Content.Server.Light.EntitySystems namespace Content.Server.Light.EntitySystems
{ {
@@ -33,11 +34,8 @@ namespace Content.Server.Light.EntitySystems
public sealed class PoweredLightSystem : EntitySystem public sealed class PoweredLightSystem : EntitySystem
{ {
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly SharedAmbientSoundSystem _ambientSystem = default!; [Dependency] private readonly SharedAmbientSoundSystem _ambientSystem = default!;
[Dependency] private readonly LightBulbSystem _bulbSystem = 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 SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly DeviceLinkSystem _signalSystem = default!; [Dependency] private readonly DeviceLinkSystem _signalSystem = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!;
@@ -45,7 +43,7 @@ namespace Content.Server.Light.EntitySystems
[Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly PointLightSystem _pointLight = default!; [Dependency] private readonly PointLightSystem _pointLight = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = 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); private static readonly TimeSpan ThunkDelay = TimeSpan.FromSeconds(2);
public const string LightBulbContainer = "light_bulb"; public const string LightBulbContainer = "light_bulb";
@@ -106,40 +104,7 @@ namespace Content.Server.Light.EntitySystems
if (bulbUid == null) if (bulbUid == null)
return; return;
// check if it's possible to apply burn damage to user
var userUid = args.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<GloveHeatResistanceComponent>(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 //removing a broken/burned bulb, so allow instant removal
if(TryComp<LightBulbComponent>(bulbUid.Value, out var bulb) && bulb.State != LightBulbState.Normal) if(TryComp<LightBulbComponent>(bulbUid.Value, out var bulb) && bulb.State != LightBulbState.Normal)
{ {
@@ -435,6 +400,10 @@ namespace Content.Server.Light.EntitySystems
if (softness != null) if (softness != null)
_pointLight.SetSoftness(uid, (float) softness, pointLight); _pointLight.SetSoftness(uid, (float) softness, pointLight);
} }
// light bulbs burn your hands!
if (TryComp<DamageOnInteractComponent>(uid, out var damageOnInteractComp))
_damageOnInteractSystem.SetIsDamageActiveTo((uid, damageOnInteractComp), value);
} }
public void ToggleLight(EntityUid uid, PoweredLightComponent? light = null) public void ToggleLight(EntityUid uid, PoweredLightComponent? light = null)

View File

@@ -202,20 +202,6 @@ public sealed partial class AnomalyComponent : Component
public float GrowingPointMultiplier = 1.5f; public float GrowingPointMultiplier = 1.5f;
#endregion #endregion
/// <summary>
/// The amount of damage dealt when either a player touches the anomaly
/// directly or by hitting the anomaly.
/// </summary>
[DataField(required: true)]
public DamageSpecifier AnomalyContactDamage = default!;
/// <summary>
/// The sound effect played when a player
/// burns themselves on an anomaly via contact.
/// </summary>
[DataField]
public SoundSpecifier AnomalyContactDamageSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg");
/// <summary> /// <summary>
/// A prototype entity that appears when an anomaly supercrit collapse. /// A prototype entity that appears when an anomaly supercrit collapse.
/// </summary> /// </summary>

View File

@@ -30,7 +30,6 @@ public abstract class SharedAnomalySystem : EntitySystem
[Dependency] private readonly INetManager _net = default!; [Dependency] private readonly INetManager _net = default!;
[Dependency] protected readonly IRobustRandom Random = default!; [Dependency] protected readonly IRobustRandom Random = default!;
[Dependency] protected readonly ISharedAdminLogManager AdminLog = default!; [Dependency] protected readonly ISharedAdminLogManager AdminLog = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] protected readonly SharedAudioSystem Audio = default!; [Dependency] protected readonly SharedAudioSystem Audio = default!;
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!;
@@ -42,26 +41,10 @@ public abstract class SharedAnomalySystem : EntitySystem
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<AnomalyComponent, InteractHandEvent>(OnInteractHand);
SubscribeLocalEvent<AnomalyComponent, AttackedEvent>(OnAttacked);
SubscribeLocalEvent<AnomalyComponent, MeleeThrowOnHitStartEvent>(OnAnomalyThrowStart); SubscribeLocalEvent<AnomalyComponent, MeleeThrowOnHitStartEvent>(OnAnomalyThrowStart);
SubscribeLocalEvent<AnomalyComponent, MeleeThrowOnHitEndEvent>(OnAnomalyThrowEnd); SubscribeLocalEvent<AnomalyComponent, MeleeThrowOnHitEndEvent>(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<CorePoweredThrowerComponent>(args.Used))
return;
DoAnomalyBurnDamage(uid, args.User, component);
}
private void OnAnomalyThrowStart(Entity<AnomalyComponent> ent, ref MeleeThrowOnHitStartEvent args) private void OnAnomalyThrowStart(Entity<AnomalyComponent> ent, ref MeleeThrowOnHitStartEvent args)
{ {
if (!TryComp<CorePoweredThrowerComponent>(args.Used, out var corePowered) || !TryComp<PhysicsComponent>(ent, out var body)) if (!TryComp<CorePoweredThrowerComponent>(args.Used, out var corePowered) || !TryComp<PhysicsComponent>(ent, out var body))
@@ -75,15 +58,6 @@ public abstract class SharedAnomalySystem : EntitySystem
_physics.SetBodyType(ent, BodyType.Static); _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) public void DoAnomalyPulse(EntityUid uid, AnomalyComponent? component = null)
{ {
if (!Resolve(uid, ref component)) if (!Resolve(uid, ref component))

View File

@@ -0,0 +1,47 @@
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Damage.Components;
/// <summary>
/// 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.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class DamageOnAttackedComponent : Component
{
/// <summary>
/// How much damage to apply to the person making contact
/// </summary>
[DataField(required: true), AutoNetworkedField]
public DamageSpecifier Damage = default!;
/// <summary>
/// Whether the damage should be resisted by a person's armor values
/// and the <see cref="DamageOnAttackedProtectionComponent"/>
/// </summary>
[DataField]
public bool IgnoreResistances = false;
/// <summary>
/// What kind of localized text should pop up when they interact with the entity
/// </summary>
[DataField]
public LocId? PopupText;
/// <summary>
/// The sound that should be made when interacting with the entity
/// </summary>
[DataField]
public SoundSpecifier InteractSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg");
/// <summary>
/// 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
/// </summary>
[DataField, AutoNetworkedField]
public bool IsDamageActive = true;
}

View File

@@ -0,0 +1,29 @@
using Content.Shared.Inventory;
using Robust.Shared.GameStates;
namespace Content.Shared.Damage.Components;
/// <summary>
/// This component is added to entities to protect them from being damaged
/// when attacking objects with the <see cref="DamageOnAttackedComponent"/>
/// If the entity has sufficient protection, the entity will take no damage.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class DamageOnAttackedProtectionComponent : Component, IClothingSlots
{
/// <summary>
/// How much and what kind of damage to protect the user from
/// when interacting with something with <see cref="DamageOnInteractComponent"/>
/// </summary>
[DataField(required: true)]
public DamageModifierSet DamageProtection = default!;
/// <summary>
/// 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
/// </summary>
[DataField]
public SlotFlags Slots { get; set; } = SlotFlags.WITHOUT_POCKET;
}

View File

@@ -0,0 +1,47 @@
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Damage.Components;
/// <summary>
/// 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.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class DamageOnInteractComponent : Component
{
/// <summary>
/// How much damage to apply to the person making contact
/// </summary>
[DataField(required: true), AutoNetworkedField]
public DamageSpecifier Damage = default!;
/// <summary>
/// Whether the damage should be resisted by a person's armor values
/// and the <see cref="DamageOnInteractProtectionComponent"/>
/// </summary>
[DataField]
public bool IgnoreResistances;
/// <summary>
/// What kind of localized text should pop up when they interact with the entity
/// </summary>
[DataField]
public LocId? PopupText;
/// <summary>
/// The sound that should be made when interacting with the entity
/// </summary>
[DataField]
public SoundSpecifier InteractSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg");
/// <summary>
/// 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
/// </summary>
[DataField, AutoNetworkedField]
public bool IsDamageActive = true;
}

View File

@@ -0,0 +1,29 @@
using Content.Shared.Inventory;
using Robust.Shared.GameStates;
namespace Content.Shared.Damage.Components;
/// <summary>
/// This component is added to entities to protect them from being damaged
/// when interacting with objects with the <see cref="DamageOnInteractComponent"/>
/// If the entity has sufficient protection, interaction with the object is not cancelled.
/// This allows the user to do things like remove a lightbulb.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class DamageOnInteractProtectionComponent : Component, IClothingSlots
{
/// <summary>
/// How much and what kind of damage to protect the user from
/// when interacting with something with <see cref="DamageOnInteractComponent"/>
/// </summary>
[DataField(required: true)]
public DamageModifierSet DamageProtection = default!;
/// <summary>
/// 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
/// </summary>
[DataField]
public SlotFlags Slots { get; set; } = SlotFlags.GLOVES;
}

View File

@@ -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<DamageOnAttackedComponent, AttackedEvent>(OnAttacked);
}
/// <summary>
/// Damages the user that attacks the entity and potentially
/// plays a sound or pops up text in response
/// </summary>
/// <param name="entity">The entity being hit</param>
/// <param name="args">Contains the user that hit the entity</param>
private void OnAttacked(Entity<DamageOnAttackedComponent> 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<DamageOnAttackedProtectionComponent>(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<HandsComponent>(args.User, out var handsComp))
{
if (_handsSystem.TryGetActiveItem((args.User, handsComp), out var itemInHand) &&
TryComp<DamageOnAttackedProtectionComponent>(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<DamageOnAttackedProtectionComponent>(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<DamageOnAttackedComponent> entity, bool mode)
{
if (entity.Comp.IsDamageActive == mode)
return;
entity.Comp.IsDamageActive = mode;
Dirty(entity);
}
}

View File

@@ -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<DamageOnInteractComponent, InteractHandEvent>(OnHandInteract);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="entity">The entity being interacted with</param>
/// <param name="args">Contains the user that interacted with the entity</param>
private void OnHandInteract(Entity<DamageOnInteractComponent> 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<DamageOnInteractProtectionComponent>(args.User, out var protectiveEntity);
// or checking the entity for the comp itself if the inventory didn't work
if (protectiveEntity.Comp == null && TryComp<DamageOnInteractProtectionComponent>(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<DamageOnInteractComponent> entity, bool mode)
{
if (entity.Comp.IsDamageActive == mode)
return;
entity.Comp.IsDamageActive = mode;
Dirty(entity);
}
}

View File

@@ -30,7 +30,7 @@ public partial class InventorySystem : EntitySystem
/// <summary> /// <summary>
/// Tries to find an entity in the specified slot with the specified component. /// Tries to find an entity in the specified slot with the specified component.
/// </summary> /// </summary>
public bool TryGetInventoryEntity<T>(Entity<InventoryComponent?> entity, out EntityUid targetUid) public bool TryGetInventoryEntity<T>(Entity<InventoryComponent?> entity, out Entity<T?> target)
where T : IComponent, IClothingSlots where T : IComponent, IClothingSlots
{ {
if (TryGetContainerSlotEnumerator(entity.Owner, out var containerSlotEnumerator)) if (TryGetContainerSlotEnumerator(entity.Owner, out var containerSlotEnumerator))
@@ -43,12 +43,12 @@ public partial class InventorySystem : EntitySystem
if ((((IClothingSlots) required).Slots & slot.SlotFlags) == 0x0) if ((((IClothingSlots) required).Slots & slot.SlotFlags) == 0x0)
continue; continue;
targetUid = item; target = (item, required);
return true; return true;
} }
} }
targetUid = EntityUid.Invalid; target = EntityUid.Invalid;
return false; return false;
} }

View File

@@ -23,6 +23,10 @@
tags: tags:
- ClothMade - ClothMade
- WhitelistChameleon - WhitelistChameleon
- type: DamageOnInteractProtection
damageProtection:
flatReductions:
Heat: 5 # the average lightbulb only does around four damage!
- type: entity - type: entity
abstract: true abstract: true

View File

@@ -283,8 +283,6 @@
color: "#535353" color: "#535353"
- type: Clothing - type: Clothing
sprite: Clothing/Hands/Gloves/Color/black.rsi sprite: Clothing/Hands/Gloves/Color/black.rsi
- type: GloveHeatResistance
heatResistance: 1400
- type: Butcherable - type: Butcherable
butcheringType: Knife butcheringType: Knife
spawned: spawned:
@@ -305,8 +303,6 @@
sprite: Clothing/Hands/Gloves/Color/yellow.rsi sprite: Clothing/Hands/Gloves/Color/yellow.rsi
- type: Clothing - type: Clothing
sprite: Clothing/Hands/Gloves/Color/yellow.rsi sprite: Clothing/Hands/Gloves/Color/yellow.rsi
- type: GloveHeatResistance
heatResistance: 1400
- type: Butcherable - type: Butcherable
butcheringType: Knife butcheringType: Knife
spawned: spawned:
@@ -323,9 +319,6 @@
name: budget insulated gloves name: budget insulated gloves
description: These gloves are cheap knockoffs of the coveted ones - no way this can end badly. description: These gloves are cheap knockoffs of the coveted ones - no way this can end badly.
components: components:
- type: GloveHeatResistance
# can't take out lights using budgets
heatResistance: 0
- type: RandomInsulation - type: RandomInsulation
# Why repeated numbers? So some numbers are more common, of course! # Why repeated numbers? So some numbers are more common, of course!
list: list:

View File

@@ -103,8 +103,6 @@
sprite: Clothing/Hands/Gloves/captain.rsi sprite: Clothing/Hands/Gloves/captain.rsi
- type: Clothing - type: Clothing
sprite: Clothing/Hands/Gloves/captain.rsi sprite: Clothing/Hands/Gloves/captain.rsi
- type: GloveHeatResistance
heatResistance: 1400
- type: Insulated - type: Insulated
- type: Fiber - type: Fiber
fiberMaterial: fibers-durathread fiberMaterial: fibers-durathread
@@ -169,8 +167,6 @@
sprite: Clothing/Hands/Gloves/leather.rsi sprite: Clothing/Hands/Gloves/leather.rsi
- type: Clothing - type: Clothing
sprite: Clothing/Hands/Gloves/leather.rsi sprite: Clothing/Hands/Gloves/leather.rsi
- type: GloveHeatResistance
heatResistance: 1400
- type: Fiber - type: Fiber
fiberMaterial: fibers-leather fiberMaterial: fibers-leather
fiberColor: fibers-brown fiberColor: fibers-brown
@@ -225,8 +221,6 @@
enum.ToggleVisuals.Layer: enum.ToggleVisuals.Layer:
True: {state: icon-green} True: {state: icon-green}
False: {state: icon} False: {state: icon}
- type: GloveHeatResistance
heatResistance: 1400
- type: Insulated - type: Insulated
- type: Fiber - type: Fiber
fiberMaterial: fibers-nanomachines fiberMaterial: fibers-nanomachines
@@ -270,8 +264,6 @@
sprite: Clothing/Hands/Gloves/combat.rsi sprite: Clothing/Hands/Gloves/combat.rsi
- type: Clothing - type: Clothing
sprite: Clothing/Hands/Gloves/combat.rsi sprite: Clothing/Hands/Gloves/combat.rsi
- type: GloveHeatResistance
heatResistance: 1400
- type: Insulated - type: Insulated
- type: Fiber - type: Fiber
fiberMaterial: fibers-insulative fiberMaterial: fibers-insulative
@@ -287,8 +279,6 @@
sprite: Clothing/Hands/Gloves/tacticalmaidgloves.rsi sprite: Clothing/Hands/Gloves/tacticalmaidgloves.rsi
- type: Clothing - type: Clothing
sprite: Clothing/Hands/Gloves/tacticalmaidgloves.rsi sprite: Clothing/Hands/Gloves/tacticalmaidgloves.rsi
- type: GloveHeatResistance
heatResistance: 1400
- type: Insulated - type: Insulated
- type: Fiber - type: Fiber
fiberColor: fibers-black fiberColor: fibers-black
@@ -324,6 +314,10 @@
- type: Fiber - type: Fiber
fiberMaterial: fibers-synthetic fiberMaterial: fibers-synthetic
fiberColor: fibers-black fiberColor: fibers-black
- type: DamageOnInteractProtection
damageProtection:
flatReductions:
Heat: 0 # no protection
- type: entity - type: entity
parent: ClothingHandsBase parent: ClothingHandsBase
@@ -338,6 +332,10 @@
- type: Fiber - type: Fiber
fiberMaterial: fibers-insulative fiberMaterial: fibers-insulative
fiberColor: fibers-yellow fiberColor: fibers-yellow
- type: DamageOnInteractProtection
damageProtection:
flatReductions:
Heat: 0 # no protection
- type: entity - type: entity
parent: ClothingHandsButcherable parent: ClothingHandsButcherable
@@ -352,6 +350,10 @@
- type: Fiber - type: Fiber
fiberMaterial: fibers-insulative fiberMaterial: fibers-insulative
fiberColor: fibers-olive fiberColor: fibers-olive
- type: DamageOnInteractProtection
damageProtection:
flatReductions:
Heat: 0 # no protection
- type: entity - type: entity
# Intentionally named after regular gloves, they're meant to be sneaky. # Intentionally named after regular gloves, they're meant to be sneaky.

View File

@@ -136,6 +136,11 @@
- WhitelistChameleon - WhitelistChameleon
- type: ClothingRequiredStepTriggerImmune - type: ClothingRequiredStepTriggerImmune
slots: WITHOUT_POCKET slots: WITHOUT_POCKET
- type: DamageOnInteractProtection
damageProtection:
flatReductions:
Heat: 10 # the average lightbulb only does around four damage!
slots: OUTERCLOTHING
- type: entity - type: entity
abstract: true abstract: true
@@ -156,6 +161,11 @@
size: Huge size: Huge
- type: ClothingRequiredStepTriggerImmune - type: ClothingRequiredStepTriggerImmune
slots: WITHOUT_POCKET slots: WITHOUT_POCKET
- type: DamageOnInteractProtection
damageProtection:
flatReductions:
Heat: 10 # the average lightbulb only does around four damage!
slots: OUTERCLOTHING
- type: entity - type: entity
parent: ClothingOuterBase parent: ClothingOuterBase

View File

@@ -230,6 +230,10 @@
- Cyborgs - Cyborgs
- Robotics - Robotics
- type: StepTriggerImmune - type: StepTriggerImmune
- type: DamageOnInteractProtection
damageProtection:
flatReductions:
Heat: 10 # capable of touching light bulbs and stoves without feeling pain!
- type: entity - type: entity
abstract: true abstract: true

View File

@@ -110,9 +110,6 @@
collection: BananiumHorn collection: BananiumHorn
params: params:
volume: 5 volume: 5
anomalyContactDamage:
types:
Radiation: 10
- type: Input - type: Input
context: "human" context: "human"
- type: Bloodstream - type: Bloodstream
@@ -158,9 +155,6 @@
suffix: "Ice" suffix: "Ice"
components: components:
- type: Anomaly - type: Anomaly
anomalyContactDamage:
types:
Cold: 10
- type: ExplosionAnomaly - type: ExplosionAnomaly
supercriticalExplosion: Cryo supercriticalExplosion: Cryo
explosionTotalIntensity: 1000 explosionTotalIntensity: 1000

View File

@@ -147,3 +147,10 @@
- type: ContainerContainer - type: ContainerContainer
containers: containers:
core_slot: !type:ContainerSlot core_slot: !type:ContainerSlot
- type: DamageOnAttackedProtection
damageProtection:
flatReductions:
Heat: 100
Cold: 100
Radiation: 100
slots: NONE

View File

@@ -154,7 +154,7 @@
- type: DisarmMalus - type: DisarmMalus
- type: entity - type: entity
name: The Throngler name: Throngler
parent: BaseSword parent: BaseSword
id: Throngler id: Throngler
description: Why would you make this? description: Why would you make this?
@@ -180,3 +180,6 @@
size: Ginormous size: Ginormous
sprite: Objects/Weapons/Melee/Throngler-in-hand.rsi sprite: Objects/Weapons/Melee/Throngler-in-hand.rsi
- type: DisarmMalus - type: DisarmMalus
- type: Grammar
attributes:
proper: true

View File

@@ -89,9 +89,6 @@
enabled: false enabled: false
- type: PoweredLight - type: PoweredLight
bulb: Tube bulb: Tube
damage:
types:
Heat: 2
- type: ContainerContainer - type: ContainerContainer
containers: containers:
light_bulb: !type:ContainerSlot light_bulb: !type:ContainerSlot
@@ -117,6 +114,11 @@
on: base on: base
broken: broken broken: broken
burned: burned burned: burned
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: Poweredlight id: Poweredlight
@@ -130,15 +132,17 @@
enabled: true enabled: true
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LightTube hasLampOnSpawn: LightTube
damage:
types:
Heat: 2
- type: AmbientOnPowered - type: AmbientOnPowered
- type: AmbientSound - type: AmbientSound
volume: -15 volume: -15
range: 2 range: 2
sound: sound:
path: /Audio/Ambience/Objects/light_hum.ogg path: /Audio/Ambience/Objects/light_hum.ogg
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
#LED lights #LED lights
- type: entity - type: entity
@@ -149,14 +153,16 @@
components: components:
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LedLightTube hasLampOnSpawn: LedLightTube
damage:
types:
Heat: 1 #LEDs don't get as hot
- type: PointLight - type: PointLight
radius: 15 radius: 15
energy: 1 energy: 1
softness: 0.9 softness: 0.9
color: "#EEEEFF" color: "#EEEEFF"
- type: DamageOnInteract
damage:
types:
Heat: 1 # LEDs don't get as hot
popupText: powered-light-component-burn-hand
- type: entity - type: entity
parent: AlwaysPoweredWallLight parent: AlwaysPoweredWallLight
@@ -178,9 +184,11 @@
components: components:
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: ExteriorLightTube hasLampOnSpawn: ExteriorLightTube
- type: DamageOnInteract
damage: damage:
types: types:
Heat: 4 #brighter light gets hotter Heat: 4 # brighter light gets hotter
popupText: powered-light-component-burn-hand
- type: entity - type: entity
parent: AlwaysPoweredWallLight parent: AlwaysPoweredWallLight
@@ -202,14 +210,16 @@
components: components:
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: SodiumLightTube hasLampOnSpawn: SodiumLightTube
damage:
types:
Heat: 2
- type: PointLight - type: PointLight
radius: 10 radius: 10
energy: 2.5 energy: 2.5
softness: 0.9 softness: 0.9
color: "#FFAF38" color: "#FFAF38"
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
parent: AlwaysPoweredWallLight parent: AlwaysPoweredWallLight
@@ -289,9 +299,6 @@
light_bulb: !type:ContainerSlot light_bulb: !type:ContainerSlot
- type: PoweredLight - type: PoweredLight
bulb: Bulb bulb: Bulb
damage:
types:
Heat: 2
- type: ApcPowerReceiver - type: ApcPowerReceiver
- type: ExtensionCableReceiver - type: ExtensionCableReceiver
- type: DeviceNetwork - type: DeviceNetwork
@@ -312,6 +319,11 @@
- On - On
- Off - Off
- Toggle - Toggle
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: PoweredLEDSmallLight id: PoweredLEDSmallLight
@@ -328,9 +340,11 @@
color: "#EEEEFF" color: "#EEEEFF"
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LedLightBulb hasLampOnSpawn: LedLightBulb
- type: DamageOnInteract
damage: damage:
types: types:
Heat: 1 Heat: 1
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: PoweredSmallLight id: PoweredSmallLight
@@ -343,9 +357,11 @@
enabled: true enabled: true
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LightBulb hasLampOnSpawn: LightBulb
- type: DamageOnInteract
damage: damage:
types: types:
Heat: 2 Heat: 2
popupText: powered-light-component-burn-hand
#Emergency Lights #Emergency Lights
- type: entity - type: entity
@@ -398,14 +414,16 @@
components: components:
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LightTubeCrystalCyan hasLampOnSpawn: LightTubeCrystalCyan
damage:
types:
Heat: 2
- type: PointLight - type: PointLight
radius: 8 radius: 8
energy: 3 energy: 3
softness: 0.5 softness: 0.5
color: "#47f8ff" color: "#47f8ff"
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: AlwaysPoweredlightCyan id: AlwaysPoweredlightCyan
@@ -425,14 +443,16 @@
components: components:
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LightTubeCrystalBlue hasLampOnSpawn: LightTubeCrystalBlue
damage:
types:
Heat: 2
- type: PointLight - type: PointLight
radius: 8 radius: 8
energy: 3 energy: 3
softness: 0.5 softness: 0.5
color: "#39a1ff" color: "#39a1ff"
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: AlwaysPoweredlightBlue id: AlwaysPoweredlightBlue
@@ -452,14 +472,16 @@
components: components:
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LightTubeCrystalPink hasLampOnSpawn: LightTubeCrystalPink
damage:
types:
Heat: 2
- type: PointLight - type: PointLight
radius: 8 radius: 8
energy: 3 energy: 3
softness: 0.5 softness: 0.5
color: "#ff66cc" color: "#ff66cc"
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: AlwaysPoweredlightPink id: AlwaysPoweredlightPink
@@ -479,14 +501,16 @@
components: components:
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LightTubeCrystalOrange hasLampOnSpawn: LightTubeCrystalOrange
damage:
types:
Heat: 2
- type: PointLight - type: PointLight
radius: 8 radius: 8
energy: 3 energy: 3
softness: 0.5 softness: 0.5
color: "#ff8227" color: "#ff8227"
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: AlwaysPoweredlightOrange id: AlwaysPoweredlightOrange
@@ -506,14 +530,16 @@
components: components:
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LightTubeCrystalRed hasLampOnSpawn: LightTubeCrystalRed
damage:
types:
Heat: 2
- type: PointLight - type: PointLight
radius: 8 radius: 8
energy: 3 energy: 3
softness: 0.5 softness: 0.5
color: "#fb4747" color: "#fb4747"
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: AlwaysPoweredlightRed id: AlwaysPoweredlightRed
@@ -533,14 +559,16 @@
components: components:
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LightTubeCrystalGreen hasLampOnSpawn: LightTubeCrystalGreen
damage:
types:
Heat: 2
- type: PointLight - type: PointLight
radius: 8 radius: 8
energy: 3 energy: 3
softness: 0.5 softness: 0.5
color: "#52ff39" color: "#52ff39"
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: AlwaysPoweredlightGreen id: AlwaysPoweredlightGreen

View File

@@ -77,9 +77,6 @@
enabled: false enabled: false
- type: PoweredLight - type: PoweredLight
bulb: Tube bulb: Tube
damage:
types:
Heat: 2
- type: ContainerContainer - type: ContainerContainer
containers: containers:
light_bulb: !type:ContainerSlot light_bulb: !type:ContainerSlot
@@ -108,6 +105,11 @@
on: base on: base
broken: broken broken: broken
burned: burned burned: burned
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: PoweredLightPostSmall id: PoweredLightPostSmall
@@ -122,9 +124,6 @@
enabled: true enabled: true
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LightTube hasLampOnSpawn: LightTube
damage:
types:
Heat: 2
- type: StaticPrice - type: StaticPrice
price: 25 price: 25
- type: AmbientOnPowered - type: AmbientOnPowered
@@ -133,6 +132,11 @@
range: 3 range: 3
sound: sound:
path: /Audio/Ambience/Objects/light_hum.ogg path: /Audio/Ambience/Objects/light_hum.ogg
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: PoweredLEDLightPostSmall id: PoweredLEDLightPostSmall
@@ -151,9 +155,6 @@
color: "#EEEEFF" color: "#EEEEFF"
- type: PoweredLight - type: PoweredLight
hasLampOnSpawn: LedLightTube hasLampOnSpawn: LedLightTube
damage:
types:
Heat: 1
- type: StaticPrice - type: StaticPrice
price: 25 price: 25
- type: AmbientOnPowered - type: AmbientOnPowered
@@ -162,3 +163,8 @@
range: 3 range: 3
sound: sound:
path: /Audio/Ambience/Objects/light_hum.ogg path: /Audio/Ambience/Objects/light_hum.ogg
- type: DamageOnInteract
damage:
types:
Heat: 1
popupText: powered-light-component-burn-hand

View File

@@ -87,9 +87,6 @@
- type: PoweredLight - type: PoweredLight
bulb: Bulb bulb: Bulb
on: false on: false
damage:
types:
Heat: 2
- type: ApcPowerReceiver - type: ApcPowerReceiver
- type: ExtensionCableReceiver - type: ExtensionCableReceiver
- type: DeviceNetwork - type: DeviceNetwork
@@ -113,6 +110,11 @@
- type: Construction - type: Construction
graph: LightFixture graph: LightFixture
node: strobeLight node: strobeLight
- type: DamageOnInteract
damage:
types:
Heat: 2
popupText: powered-light-component-burn-hand
- type: entity - type: entity
id: PoweredStrobeLightPolice id: PoweredStrobeLightPolice

View File

@@ -9,9 +9,6 @@
collection: RadiationPulse collection: RadiationPulse
params: params:
volume: 5 volume: 5
anomalyContactDamage:
types:
Radiation: 10
- type: AmbientSound - type: AmbientSound
range: 5 range: 5
volume: -5 volume: -5
@@ -51,6 +48,15 @@
- type: SecretDataAnomaly - type: SecretDataAnomaly
randomStartSecretMin: 0 randomStartSecretMin: 0
randomStartSecretMax: 2 randomStartSecretMax: 2
- type: DamageOnInteract
damage:
types:
Radiation: 10
popupText: anomaly-component-contact-damage
- type: DamageOnAttacked
damage:
types:
Radiation: 10
- type: entity - type: entity
id: AnomalyPyroclastic id: AnomalyPyroclastic
@@ -99,6 +105,15 @@
- type: IgniteOnCollide - type: IgniteOnCollide
fixtureId: fix1 fixtureId: fix1
fireStacks: 1 fireStacks: 1
- type: DamageOnInteract
damage:
types:
Heat: 10
popupText: anomaly-component-contact-damage
- type: DamageOnAttacked
damage:
types:
Heat: 10
- type: entity - type: entity
id: AnomalyGravity id: AnomalyGravity
@@ -294,9 +309,6 @@
collection: RadiationPulse collection: RadiationPulse
params: params:
volume: 5 volume: 5
anomalyContactDamage:
types:
Radiation: 10
- type: entity - type: entity
id: AnomalyIce id: AnomalyIce
@@ -319,9 +331,6 @@
- type: Anomaly - type: Anomaly
corePrototype: AnomalyCoreIce corePrototype: AnomalyCoreIce
coreInertPrototype: AnomalyCoreIceInert coreInertPrototype: AnomalyCoreIceInert
anomalyContactDamage:
types:
Cold: 10
- type: ExplosionAnomaly - type: ExplosionAnomaly
supercriticalExplosion: Cryo supercriticalExplosion: Cryo
explosionTotalIntensity: 300 explosionTotalIntensity: 300
@@ -345,6 +354,15 @@
releasedGas: 8 # Frezon. Please replace if there is a better way to specify this releasedGas: 8 # Frezon. Please replace if there is a better way to specify this
releaseOnMaxSeverity: true releaseOnMaxSeverity: true
spawnRadius: 0 spawnRadius: 0
- type: DamageOnInteract
damage:
types:
Cold: 10
popupText: anomaly-component-contact-damage
- type: DamageOnAttacked
damage:
types:
Cold: 10
- type: entity - type: entity
id: AnomalyRockBase id: AnomalyRockBase
@@ -609,9 +627,6 @@
coreInertPrototype: AnomalyCoreFloraInert coreInertPrototype: AnomalyCoreFloraInert
minPulseLength: 60 minPulseLength: 60
maxPulseLength: 120 maxPulseLength: 120
anomalyContactDamage:
types:
Slash: 0
- type: TileSpawnAnomaly - type: TileSpawnAnomaly
entries: entries:
- settings: - settings:
@@ -715,9 +730,6 @@
coreInertPrototype: AnomalyCoreLiquidInert coreInertPrototype: AnomalyCoreLiquidInert
minPulseLength: 60 minPulseLength: 60
maxPulseLength: 120 maxPulseLength: 120
anomalyContactDamage:
types:
Slash: 1
- type: EntitySpawnAnomaly - type: EntitySpawnAnomaly
entries: entries:
- settings: - settings:
@@ -829,9 +841,6 @@
coreInertPrototype: AnomalyCoreShadowInert coreInertPrototype: AnomalyCoreShadowInert
minPulseLength: 60 minPulseLength: 60
maxPulseLength: 120 maxPulseLength: 120
anomalyContactDamage:
types:
Cold: 10
animationTime: 4 animationTime: 4
offset: "-0.1,0.1" offset: "-0.1,0.1"
- type: EntitySpawnAnomaly - type: EntitySpawnAnomaly
@@ -857,3 +866,12 @@
- type: Tag - type: Tag
tags: tags:
- SpookyFog - SpookyFog
- type: DamageOnInteract
damage:
types:
Cold: 10
popupText: anomaly-component-contact-damage
- type: DamageOnAttacked
damage:
types:
Cold: 10

View File

@@ -24,6 +24,8 @@
bulb: Bulb bulb: Bulb
on: false on: false
hasLampOnSpawn: ServiceLightBulb hasLampOnSpawn: ServiceLightBulb
- type: DamageOnInteract
damage: damage:
types: types:
Heat: 5 Heat: 5
popupText: powered-light-component-burn-hand