diff --git a/Content.Server/Atmos/Components/BarotraumaComponent.cs b/Content.Server/Atmos/Components/BarotraumaComponent.cs
index 2e789ba4e1..9dba64a22c 100644
--- a/Content.Server/Atmos/Components/BarotraumaComponent.cs
+++ b/Content.Server/Atmos/Components/BarotraumaComponent.cs
@@ -21,5 +21,10 @@ namespace Content.Server.Atmos.Components
[DataField("maxDamage")]
[ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 MaxDamage = 200;
+
+ ///
+ /// Used to keep track of when damage starts/stops. Useful for logs.
+ ///
+ public bool TakingDamage = false;
}
}
diff --git a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs
index 7dd99dd3c0..6feb108c76 100644
--- a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs
@@ -1,7 +1,9 @@
using System;
using System.Data;
+using Content.Server.Administration.Logs;
using Content.Server.Alert;
using Content.Server.Atmos.Components;
+using Content.Shared.Administration.Logs;
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Damage;
@@ -15,6 +17,7 @@ namespace Content.Server.Atmos.EntitySystems
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
private const float UpdateTimer = 1f;
@@ -105,6 +108,12 @@ namespace Content.Server.Atmos.EntitySystems
// Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear.
_damageableSystem.TryChangeDamage(uid, barotrauma.Damage * Atmospherics.LowPressureDamage, true, false);
+ if (!barotrauma.TakingDamage)
+ {
+ barotrauma.TakingDamage = true;
+ _logSystem.Add(LogType.Barotrauma, $"{barotrauma.Owner} started taking low pressure damage");
+ }
+
if (status == null) break;
if (pressure <= Atmospherics.HazardLowPressure)
@@ -128,6 +137,12 @@ namespace Content.Server.Atmos.EntitySystems
// Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear.
_damageableSystem.TryChangeDamage(uid, barotrauma.Damage * damageScale, true, false);
+ if (!barotrauma.TakingDamage)
+ {
+ barotrauma.TakingDamage = true;
+ _logSystem.Add(LogType.Barotrauma, $"{barotrauma.Owner} started taking high pressure damage");
+ }
+
if (status == null) break;
if (pressure >= Atmospherics.HazardHighPressure)
@@ -141,6 +156,11 @@ namespace Content.Server.Atmos.EntitySystems
// Normal pressure.
default:
+ if (barotrauma.TakingDamage)
+ {
+ barotrauma.TakingDamage = false;
+ _logSystem.Add(LogType.Barotrauma, $"{barotrauma.Owner} stopped taking pressure damage");
+ }
status?.ClearAlertCategory(AlertCategory.Pressure);
break;
}
diff --git a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs
index 2bfb1feb35..461e4d1257 100644
--- a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
+using Content.Server.Administration.Logs;
using Content.Server.Alert;
using Content.Server.Atmos.Components;
using Content.Server.Stunnable;
using Content.Server.Temperature.Systems;
using Content.Shared.ActionBlocker;
+using Content.Shared.Administration.Logs;
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Damage;
@@ -26,6 +28,7 @@ namespace Content.Server.Atmos.EntitySystems
[Dependency] private readonly StunSystem _stunSystem = default!;
[Dependency] private readonly TemperatureSystem _temperatureSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
private const float MinimumFireStacks = -10f;
private const float MaximumFireStacks = 20f;
@@ -140,6 +143,7 @@ namespace Content.Server.Atmos.EntitySystems
if (!flammable.OnFire)
return;
+ _logSystem.Add(LogType.Flammable, $"{flammable.Owner} stopped being on fire damage");
flammable.OnFire = false;
flammable.FireStacks = 0;
@@ -155,6 +159,7 @@ namespace Content.Server.Atmos.EntitySystems
if (flammable.FireStacks > 0 && !flammable.OnFire)
{
+ _logSystem.Add(LogType.Flammable, $"{flammable.Owner} is on fire");
flammable.OnFire = true;
}
diff --git a/Content.Server/Body/Components/RespiratorComponent.cs b/Content.Server/Body/Components/RespiratorComponent.cs
index 00bf65fe84..2f5e5e1ef6 100644
--- a/Content.Server/Body/Components/RespiratorComponent.cs
+++ b/Content.Server/Body/Components/RespiratorComponent.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Content.Server.Administration.Logs;
using Content.Server.Alert;
using Content.Server.Atmos;
using Content.Server.Atmos.EntitySystems;
@@ -8,6 +9,7 @@ using Content.Server.Body.Behavior;
using Content.Server.Temperature.Components;
using Content.Server.Temperature.Systems;
using Content.Shared.ActionBlocker;
+using Content.Shared.Administration.Logs;
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Body.Components;
@@ -313,6 +315,9 @@ namespace Content.Server.Body.Components
private void TakeSuffocationDamage()
{
+ if (!Suffocating)
+ EntitySystem.Get().Add(LogType.Asphyxiation, $"{Owner} started suffocating");
+
Suffocating = true;
if (Owner.TryGetComponent(out ServerAlertsComponent? alertsComponent))
@@ -325,6 +330,9 @@ namespace Content.Server.Body.Components
private void StopSuffocation()
{
+ if (Suffocating)
+ EntitySystem.Get().Add(LogType.Asphyxiation, $"{Owner} stopped suffocating");
+
Suffocating = false;
if (Owner.TryGetComponent(out ServerAlertsComponent? alertsComponent))
diff --git a/Content.Server/Chat/Commands/SuicideCommand.cs b/Content.Server/Chat/Commands/SuicideCommand.cs
index a9ba9f309d..b502c7ca2a 100644
--- a/Content.Server/Chat/Commands/SuicideCommand.cs
+++ b/Content.Server/Chat/Commands/SuicideCommand.cs
@@ -1,12 +1,14 @@
using System.Linq;
using Content.Server.Act;
using Content.Server.Administration;
+using Content.Server.Administration.Logs;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Players;
using Content.Server.Popups;
+using Content.Shared.Administration.Logs;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Popups;
@@ -81,6 +83,8 @@ namespace Content.Server.Chat.Commands
//TODO: needs to check if the mob is actually alive
//TODO: maybe set a suicided flag to prevent resurrection?
+ EntitySystem.Get().Add(LogType.Suicide, $"{player.AttachedEntity} is committing suicide");
+
// Held item suicide
var handsComponent = owner.GetComponent();
var itemComponent = handsComponent.GetActiveHand;
diff --git a/Content.Server/Damage/Systems/DamageOnHighSpeedImpactSystem.cs b/Content.Server/Damage/Systems/DamageOnHighSpeedImpactSystem.cs
index afa5d947f0..f0db7dc5f0 100644
--- a/Content.Server/Damage/Systems/DamageOnHighSpeedImpactSystem.cs
+++ b/Content.Server/Damage/Systems/DamageOnHighSpeedImpactSystem.cs
@@ -1,7 +1,9 @@
using System;
+using Content.Server.Administration.Logs;
using Content.Server.Damage.Components;
using Content.Server.Stunnable;
using Content.Server.Stunnable.Components;
+using Content.Shared.Administration.Logs;
using Content.Shared.Audio;
using Content.Shared.Damage;
using Content.Shared.Stunnable;
@@ -23,6 +25,7 @@ namespace Content.Server.Damage.Systems
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly StunSystem _stunSystem = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
public override void Initialize()
{
@@ -50,7 +53,11 @@ namespace Content.Server.Damage.Systems
_stunSystem.TryStun(uid, TimeSpan.FromSeconds(component.StunSeconds));
var damageScale = (speed / component.MinimumSpeed) * component.Factor;
- _damageableSystem.TryChangeDamage(uid, component.Damage * damageScale);
+
+ var dmg = _damageableSystem.TryChangeDamage(uid, component.Damage * damageScale);
+
+ if (dmg != null)
+ _logSystem.Add(LogType.Damaged, $"{component.Owner} took {dmg.Total} damage from a high speed collision");
}
}
}
diff --git a/Content.Server/Damage/Systems/DamageOnLandSystem.cs b/Content.Server/Damage/Systems/DamageOnLandSystem.cs
index ba2b789a1b..48dbe4f997 100644
--- a/Content.Server/Damage/Systems/DamageOnLandSystem.cs
+++ b/Content.Server/Damage/Systems/DamageOnLandSystem.cs
@@ -1,4 +1,6 @@
+using Content.Server.Administration.Logs;
using Content.Server.Damage.Components;
+using Content.Shared.Administration.Logs;
using Content.Shared.Damage;
using Content.Shared.Throwing;
using Robust.Shared.GameObjects;
@@ -9,6 +11,7 @@ namespace Content.Server.Damage.Systems
public sealed class DamageOnLandSystem : EntitySystem
{
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
public override void Initialize()
{
@@ -18,7 +21,11 @@ namespace Content.Server.Damage.Systems
private void DamageOnLand(EntityUid uid, DamageOnLandComponent component, LandEvent args)
{
- _damageableSystem.TryChangeDamage(uid, component.Damage, component.IgnoreResistances);
+ var dmg = _damageableSystem.TryChangeDamage(uid, component.Damage, component.IgnoreResistances);
+ if (dmg == null)
+ return;
+
+ _logSystem.Add(LogType.Landed, $"{component.Owner} received {dmg.Total} damage from landing");
}
}
}
diff --git a/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs b/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs
index 225ff9ae76..9b75e34e44 100644
--- a/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs
+++ b/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs
@@ -1,5 +1,7 @@
+using Content.Server.Administration.Logs;
using Content.Server.Damage.Components;
using Content.Server.Tools.Components;
+using Content.Shared.Administration.Logs;
using Content.Shared.Damage;
using Content.Shared.Interaction;
using Robust.Shared.GameObjects;
@@ -10,6 +12,7 @@ namespace Content.Server.Damage.Systems
public class DamageOnToolInteractSystem : EntitySystem
{
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
public override void Initialize()
{
@@ -27,18 +30,25 @@ namespace Content.Server.Damage.Systems
&& args.Used.TryGetComponent(out var welder)
&& welder.Lit)
{
- _damageableSystem.TryChangeDamage(args.Target.Uid, weldingDamage);
- args.Handled = true;
- return;
- }
+ var dmg = _damageableSystem.TryChangeDamage(args.Target.Uid, weldingDamage);
- if (component.DefaultDamage is {} damage
+ if (dmg != null)
+ _logSystem.Add(LogType.Damaged,
+ $"{args.User} used {args.Used} as a welder to deal {dmg.Total} damage to {args.Target}");
+
+ args.Handled = true;
+ }
+ else if (component.DefaultDamage is {} damage
&& args.Used.TryGetComponent(out var tool)
&& tool.Qualities.ContainsAny(component.Tools))
{
- _damageableSystem.TryChangeDamage(args.Target.Uid, damage);
+ var dmg = _damageableSystem.TryChangeDamage(args.Target.Uid, damage);
+
+ if (dmg != null)
+ _logSystem.Add(LogType.Damaged,
+ $"{args.User} used {args.Used} as a tool to deal {dmg.Total} damage to {args.Target}");
+
args.Handled = true;
- return;
}
}
}
diff --git a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs
index 900ded4802..98ea41dd0b 100644
--- a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs
+++ b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs
@@ -1,4 +1,6 @@
+using Content.Server.Administration.Logs;
using Content.Server.Damage.Components;
+using Content.Shared.Administration.Logs;
using Content.Shared.Damage;
using Content.Shared.Throwing;
using Robust.Shared.GameObjects;
@@ -9,7 +11,8 @@ namespace Content.Server.Damage.Systems
public class DamageOtherOnHitSystem : EntitySystem
{
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
-
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
+
public override void Initialize()
{
SubscribeLocalEvent(OnDoHit);
@@ -17,7 +20,9 @@ namespace Content.Server.Damage.Systems
private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args)
{
- _damageableSystem.TryChangeDamage(args.Target.Uid, component.Damage, component.IgnoreResistances);
+ var dmg = _damageableSystem.TryChangeDamage(args.Target.Uid, component.Damage, component.IgnoreResistances);
+ if (dmg != null)
+ _logSystem.Add(LogType.ThrowHit, $"{args.Target} received {dmg.Total} damage from collision");
}
}
}
diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs
index 5d4f95eaac..1a09b24523 100644
--- a/Content.Server/Electrocution/ElectrocutionSystem.cs
+++ b/Content.Server/Electrocution/ElectrocutionSystem.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using Content.Server.Administration.Logs;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NodeContainer.NodeGroups;
@@ -8,6 +9,7 @@ using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Power.NodeGroups;
using Content.Server.Window;
+using Content.Shared.Administration.Logs;
using Content.Shared.Alert;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
@@ -46,6 +48,7 @@ namespace Content.Server.Electrocution
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly NodeGroupSystem _nodeGroupSystem = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
private const string StatusEffectKey = "Electrocution";
private const string DamageType = "Shock";
@@ -104,7 +107,10 @@ namespace Content.Server.Electrocution
_prototypeManager.Index(DamageType),
(int) finished.AccumulatedDamage);
- _damageableSystem.TryChangeDamage(finished.Electrocuting, damage);
+ var actual = _damageableSystem.TryChangeDamage(finished.Electrocuting, damage);
+ if (actual != null)
+ _logSystem.Add(LogType.Electrocution,
+ $"{finished.Owner} took {actual.Total} powered electrocution damage");
}
EntityManager.DeleteEntity(uid);
@@ -337,9 +343,15 @@ namespace Content.Server.Electrocution
// TODO: Sparks here.
if(shockDamage is {} dmg)
- _damageableSystem.TryChangeDamage(uid,
+ {
+ var actual = _damageableSystem.TryChangeDamage(uid,
new DamageSpecifier(_prototypeManager.Index(DamageType), dmg));
+ if (actual != null)
+ _logSystem.Add(LogType.Electrocution,
+ $"{statusEffects.Owner} took {actual.Total} powered electrocution damage");
+ }
+
_stutteringSystem.DoStutter(uid, time * StutteringTimeMultiplier, statusEffects, alerts);
_jitteringSystem.DoJitter(uid, time * JitterTimeMultiplier, JitterAmplitude, JitterFrequency, true,
statusEffects, alerts);
diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs
index 3e1ebd1d74..ff721d0c72 100644
--- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs
+++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Content.Server.Administration.Logs;
using Content.Server.Camera;
using Content.Server.Explosion.Components;
using Content.Shared.Acts;
+using Content.Shared.Administration.Logs;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Maps;
using Content.Shared.Physics;
@@ -48,6 +50,7 @@ namespace Content.Server.Explosion.EntitySystems
[Dependency] private readonly ActSystem _acts = default!;
[Dependency] private readonly EffectSystem _effects = default!;
[Dependency] private readonly TriggerSystem _triggers = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
private bool IgnoreExplosivePassable(IEntity e)
{
@@ -335,6 +338,9 @@ namespace Content.Server.Explosion.EntitySystems
return;
}
+ _logSystem.Add(LogType.Damaged, LogImpact.High ,
+ $"Spawned explosion at {epicenter} with range {devastationRange}/{heavyImpactRange}/{lightImpactRange}/{flashRange}");
+
var maxRange = MathHelper.Max(devastationRange, heavyImpactRange, lightImpactRange, 0);
var epicenterMapPos = epicenter.ToMapPos(EntityManager);
var boundingBox = new Box2(epicenterMapPos - new Vector2(maxRange, maxRange),
diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs
index 6fc0496b96..640214e96c 100644
--- a/Content.Server/Hands/Systems/HandsSystem.cs
+++ b/Content.Server/Hands/Systems/HandsSystem.cs
@@ -8,6 +8,7 @@ using Content.Server.Items;
using Content.Server.Stack;
using Content.Server.Storage.Components;
using Content.Server.Throwing;
+using Content.Shared.ActionBlocker;
using Content.Shared.Examine;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
@@ -35,6 +36,7 @@ namespace Content.Server.Hands.Systems
[Dependency] private readonly InteractionSystem _interactionSystem = default!;
[Dependency] private readonly StackSystem _stackSystem = default!;
[Dependency] private readonly HandVirtualItemSystem _virtualItemSystem = default!;
+ [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
public override void Initialize()
{
@@ -223,7 +225,7 @@ namespace Content.Server.Hands.Systems
playerEnt.IsInContainer() ||
!playerEnt.TryGetComponent(out SharedHandsComponent? hands) ||
!hands.TryGetActiveHeldEntity(out var throwEnt) ||
- !_interactionSystem.TryThrowInteraction(hands.Owner, throwEnt))
+ !_actionBlockerSystem.CanThrow(playerEnt.Uid))
return false;
if (throwEnt.TryGetComponent(out StackComponent? stack) && stack.Count > 1 && stack.ThrowIndividually)
diff --git a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs
index c51ae60002..3dfaa51d7b 100644
--- a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs
+++ b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs
@@ -22,6 +22,8 @@ using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Maths;
using Content.Shared.Audio;
+using Content.Server.Administration.Logs;
+using Content.Shared.Administration.Logs;
namespace Content.Server.Light.EntitySystems
{
@@ -35,6 +37,7 @@ namespace Content.Server.Light.EntitySystems
[Dependency] private readonly SharedAmbientSoundSystem _ambientSystem = default!;
[Dependency] private readonly LightBulbSystem _bulbSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
private static readonly TimeSpan ThunkDelay = TimeSpan.FromSeconds(2);
@@ -112,7 +115,13 @@ namespace Content.Server.Light.EntitySystems
// apply damage to users hands and show message with sound
var burnMsg = Loc.GetString("powered-light-component-burn-hand");
_popupSystem.PopupEntity(burnMsg, uid, Filter.Entities(userUid));
- _damageableSystem.TryChangeDamage(userUid, light.Damage);
+
+ var damage = _damageableSystem.TryChangeDamage(userUid, light.Damage);
+
+ if (damage != null)
+ _logSystem.Add(LogType.Damaged,
+ $"{args.User} burned their hand on {args.Target} and received {damage.Total} damage");
+
SoundSystem.Play(Filter.Pvs(uid), light.BurnHandSound.GetSound(), uid);
args.Handled = true;
diff --git a/Content.Server/Medical/Components/HealingComponent.cs b/Content.Server/Medical/Components/HealingComponent.cs
index 7bb215021a..c95db5e3ef 100644
--- a/Content.Server/Medical/Components/HealingComponent.cs
+++ b/Content.Server/Medical/Components/HealingComponent.cs
@@ -1,6 +1,8 @@
using System.Threading.Tasks;
+using Content.Server.Administration.Logs;
using Content.Server.Stack;
using Content.Shared.ActionBlocker;
+using Content.Shared.Administration.Logs;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Interaction;
@@ -62,7 +64,15 @@ namespace Content.Server.Medical.Components
return true;
}
- EntitySystem.Get().TryChangeDamage(eventArgs.Target.Uid, Damage, true);
+ var healed = EntitySystem.Get().TryChangeDamage(eventArgs.Target.Uid, Damage, true);
+
+ if (healed == null)
+ return true;
+
+ if (eventArgs.Target != eventArgs.User)
+ EntitySystem.Get().Add(LogType.Healed, $"{eventArgs.User} healed {eventArgs.Target} for {healed.Total} damage");
+ else
+ EntitySystem.Get().Add(LogType.Healed, $"{eventArgs.User} healed themselves for {healed.Total} damage");
return true;
}
diff --git a/Content.Server/Nutrition/Components/HungerComponent.cs b/Content.Server/Nutrition/Components/HungerComponent.cs
index 1b2b1d31fd..bae37a5c0a 100644
--- a/Content.Server/Nutrition/Components/HungerComponent.cs
+++ b/Content.Server/Nutrition/Components/HungerComponent.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using Content.Server.Administration.Logs;
using Content.Server.Alert;
+using Content.Shared.Administration.Logs;
using Content.Shared.Alert;
using Content.Shared.Damage;
using Content.Shared.MobState.Components;
@@ -203,6 +205,11 @@ namespace Content.Server.Nutrition.Components
// _trySound(calculatedThreshold);
if (calculatedHungerThreshold != _currentHungerThreshold)
{
+ if (_currentHungerThreshold == HungerThreshold.Dead)
+ EntitySystem.Get().Add(LogType.Hunger, $"{Owner} has stopped starving");
+ else if (calculatedHungerThreshold == HungerThreshold.Dead)
+ EntitySystem.Get().Add(LogType.Hunger, $"{Owner} has started starving");
+
_currentHungerThreshold = calculatedHungerThreshold;
HungerThresholdEffect();
Dirty();
diff --git a/Content.Server/Nutrition/Components/ThirstComponent.cs b/Content.Server/Nutrition/Components/ThirstComponent.cs
index ca7f28de31..66e7e80789 100644
--- a/Content.Server/Nutrition/Components/ThirstComponent.cs
+++ b/Content.Server/Nutrition/Components/ThirstComponent.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using Content.Server.Administration.Logs;
using Content.Server.Alert;
+using Content.Shared.Administration.Logs;
using Content.Shared.Alert;
using Content.Shared.Damage;
using Content.Shared.MobState.Components;
@@ -200,6 +202,11 @@ namespace Content.Server.Nutrition.Components
// _trySound(calculatedThreshold);
if (calculatedThirstThreshold != _currentThirstThreshold)
{
+ if (_currentThirstThreshold == ThirstThreshold.Dead)
+ EntitySystem.Get().Add(LogType.Thirst, $"{Owner} has stopped taking dehydration damage");
+ else if (calculatedThirstThreshold == ThirstThreshold.Dead)
+ EntitySystem.Get().Add(LogType.Thirst, $"{Owner} has started taking dehydration damage");
+
_currentThirstThreshold = calculatedThirstThreshold;
ThirstThresholdEffect();
Dirty();
diff --git a/Content.Server/Projectiles/ProjectileSystem.cs b/Content.Server/Projectiles/ProjectileSystem.cs
index 982f178c2c..fa5d2a4d88 100644
--- a/Content.Server/Projectiles/ProjectileSystem.cs
+++ b/Content.Server/Projectiles/ProjectileSystem.cs
@@ -57,9 +57,8 @@ namespace Content.Server.Projectiles
component.DamagedEntity = true;
if (dmg is not null && EntityManager.TryGetEntity(component.Shooter, out var shooter))
- _adminLogSystem.Add(LogType.BulletHit, LogImpact.Low, $"Bullet shot by {shooter} hit {otherEntity}");
- // "DamagedEntity" is misleading. Hit entity may be more accurate, as the damage may have been resisted
- // by resistance sets.
+ _adminLogSystem.Add(LogType.BulletHit, LogImpact.Low,
+ $"Projectile {component.Owner} shot by {shooter} hit {otherEntity} and dealt {dmg.Total} damage");
}
// Damaging it can delete it
diff --git a/Content.Server/Repairable/RepairableSystem.cs b/Content.Server/Repairable/RepairableSystem.cs
index bb5b2d7921..a5471ea677 100644
--- a/Content.Server/Repairable/RepairableSystem.cs
+++ b/Content.Server/Repairable/RepairableSystem.cs
@@ -1,5 +1,7 @@
+using Content.Server.Administration.Logs;
using Content.Server.Tools;
using Content.Server.Tools.Components;
+using Content.Shared.Administration.Logs;
using Content.Shared.Damage;
using Content.Shared.Interaction;
using Content.Shared.Popups;
@@ -14,6 +16,7 @@ namespace Content.Server.Repairable
{
[Dependency] private readonly ToolSystem _toolSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
public override void Initialize()
{
@@ -32,6 +35,7 @@ namespace Content.Server.Repairable
// Repair all damage
_damageableSystem.SetAllDamage(damageable, 0);
+ _logSystem.Add(LogType.Healed, $"{args.User} repaired ${uid} back to full health");
component.Owner.PopupMessage(args.User,
Loc.GetString("comp-repairable-repair",
diff --git a/Content.Server/Temperature/Components/TemperatureComponent.cs b/Content.Server/Temperature/Components/TemperatureComponent.cs
index 9cae7cb7ee..dca4e61a0c 100644
--- a/Content.Server/Temperature/Components/TemperatureComponent.cs
+++ b/Content.Server/Temperature/Components/TemperatureComponent.cs
@@ -70,5 +70,10 @@ namespace Content.Server.Temperature.Components
[DataField("damageCap")]
[ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 DamageCap = FixedPoint2.New(8);
+
+ ///
+ /// Used to keep track of when damage starts/stops. Useful for logs.
+ ///
+ public bool TakingDamage = false;
}
}
diff --git a/Content.Server/Temperature/Systems/TemperatureSystem.cs b/Content.Server/Temperature/Systems/TemperatureSystem.cs
index e65845932c..0b27610d93 100644
--- a/Content.Server/Temperature/Systems/TemperatureSystem.cs
+++ b/Content.Server/Temperature/Systems/TemperatureSystem.cs
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Content.Server.Administration.Logs;
using Content.Server.Alert;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Temperature.Components;
+using Content.Shared.Administration.Logs;
using Content.Shared.Alert;
using Content.Shared.Damage;
using Content.Shared.FixedPoint;
@@ -17,6 +19,7 @@ namespace Content.Server.Temperature.Systems
{
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
///
/// All the components that will have their damage updated at the end of the tick.
@@ -160,17 +163,34 @@ namespace Content.Server.Temperature.Systems
if (temperature.CurrentTemperature >= temperature.HeatDamageThreshold)
{
+ if (!temperature.TakingDamage)
+ {
+ _logSystem.Add(LogType.Temperature, $"{temperature.Owner} started taking high temperature damage");
+ temperature.TakingDamage = true;
+ }
+
var diff = Math.Abs(temperature.CurrentTemperature - temperature.HeatDamageThreshold);
var tempDamage = c / (1 + a * Math.Pow(Math.E, -heatK * diff)) - y;
_damageableSystem.TryChangeDamage(uid, temperature.HeatDamage * tempDamage);
}
else if (temperature.CurrentTemperature <= temperature.ColdDamageThreshold)
{
+ if (!temperature.TakingDamage)
+ {
+ _logSystem.Add(LogType.Temperature, $"{temperature.Owner} started taking low temperature damage");
+ temperature.TakingDamage = true;
+ }
+
var diff = Math.Abs(temperature.CurrentTemperature - temperature.ColdDamageThreshold);
var tempDamage =
Math.Sqrt(diff * (Math.Pow(temperature.DamageCap.Double(), 2) / temperature.ColdDamageThreshold));
_damageableSystem.TryChangeDamage(uid, temperature.ColdDamage * tempDamage);
}
+ else if (temperature.TakingDamage)
+ {
+ _logSystem.Add(LogType.Temperature, $"{temperature.Owner} stopped taking temperature damage");
+ temperature.TakingDamage = false;
+ }
}
private void OnTemperatureChangeAttempt(EntityUid uid, TemperatureProtectionComponent component, ModifyChangedTemperatureEvent args)
diff --git a/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs
index 2ef7da23fe..1c742b3ab6 100644
--- a/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs
+++ b/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs
@@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Content.Server.Administration.Logs;
using Content.Server.Body.Components;
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Cooldown;
using Content.Server.Weapon.Melee.Components;
+using Content.Shared.Administration.Logs;
using Content.Shared.Damage;
using Content.Shared.Hands;
using Content.Shared.Interaction;
@@ -28,6 +30,7 @@ namespace Content.Server.Weapon.Melee
[Dependency] private IGameTiming _gameTiming = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private SolutionContainerSystem _solutionsSystem = default!;
+ [Dependency] private readonly AdminLogSystem _logSystem = default!;
public override void Initialize()
{
@@ -92,8 +95,19 @@ namespace Content.Server.Weapon.Melee
RaiseLocalEvent(target.Uid, new AttackedEvent(args.Used, args.User, args.ClickLocation));
- _damageableSystem.TryChangeDamage(target.Uid,
+ var damage = _damageableSystem.TryChangeDamage(target.Uid,
DamageSpecifier.ApplyModifierSets(comp.Damage, hitEvent.ModifiersList));
+
+ if (damage != null)
+ {
+ if (args.Used == args.User)
+ _logSystem.Add(LogType.MeleeHit,
+ $"{args.User} melee attacked {args.TargetEntity} using their hands and dealt {damage.Total} damage");
+ else
+ _logSystem.Add(LogType.MeleeHit,
+ $"{args.User} melee attacked {args.TargetEntity} using {args.Used} and dealt {damage.Total} damage");
+ }
+
SoundSystem.Play(Filter.Pvs(owner), comp.HitSound.GetSound(), target);
}
}
@@ -160,8 +174,18 @@ namespace Content.Server.Weapon.Melee
{
RaiseLocalEvent(entity.Uid, new AttackedEvent(args.Used, args.User, args.ClickLocation));
- _damageableSystem.TryChangeDamage(entity.Uid,
- DamageSpecifier.ApplyModifierSets(comp.Damage, hitEvent.ModifiersList));
+ var damage = _damageableSystem.TryChangeDamage(entity.Uid,
+ DamageSpecifier.ApplyModifierSets(comp.Damage, hitEvent.ModifiersList));
+
+ if (damage != null)
+ {
+ if (args.Used == args.User)
+ _logSystem.Add(LogType.MeleeHit,
+ $"{args.User} melee attacked {entity} using their hands and dealt {damage.Total} damage");
+ else
+ _logSystem.Add(LogType.MeleeHit,
+ $"{args.User} melee attacked {entity} using {args.Used} and dealt {damage.Total} damage");
+ }
}
}
diff --git a/Content.Server/Weapon/Ranged/Barrels/Components/ServerRangedBarrelComponent.cs b/Content.Server/Weapon/Ranged/Barrels/Components/ServerRangedBarrelComponent.cs
index 053a688ee3..a4a2e573e8 100644
--- a/Content.Server/Weapon/Ranged/Barrels/Components/ServerRangedBarrelComponent.cs
+++ b/Content.Server/Weapon/Ranged/Barrels/Components/ServerRangedBarrelComponent.cs
@@ -2,9 +2,11 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using Content.Server.Administration.Logs;
using Content.Server.Camera;
using Content.Server.Projectiles.Components;
using Content.Server.Weapon.Ranged.Ammunition.Components;
+using Content.Shared.Administration.Logs;
using Content.Shared.Audio;
using Content.Shared.Damage;
using Content.Shared.Examine;
@@ -396,7 +398,10 @@ namespace Content.Server.Weapon.Ranged.Barrels.Components
var result = rayCastResults[0];
var distance = result.Distance;
hitscan.FireEffects(shooter, distance, angle, result.HitEntity);
- EntitySystem.Get().TryChangeDamage(result.HitEntity.Uid, hitscan.Damage);
+ var dmg = EntitySystem.Get().TryChangeDamage(result.HitEntity.Uid, hitscan.Damage);
+ if (dmg != null)
+ EntitySystem.Get().Add(LogType.HitScanHit,
+ $"{shooter} hit {result.HitEntity} using {hitscan.Owner} and dealt {dmg.Total} damage");
}
else
{
diff --git a/Content.Shared/Administration/Logs/LogType.cs b/Content.Shared/Administration/Logs/LogType.cs
index 00a5b80355..b128de944d 100644
--- a/Content.Shared/Administration/Logs/LogType.cs
+++ b/Content.Shared/Administration/Logs/LogType.cs
@@ -40,5 +40,17 @@ public enum LogType
Pickup = 36,
Drop = 37,
BulletHit = 38,
+ MeleeHit = 41,
+ HitScanHit = 42,
+ Suicide = 43,
+ Explosion = 44,
+ Radiation = 45,
+ Barotrauma = 46,
+ Flammable = 47,
+ Asphyxiation = 48,
+ Temperature = 49,
+ Hunger = 50,
+ Thirst = 51,
+ Electrocution = 52,
CrayonDraw = 39,
}
diff --git a/Content.Shared/Damage/Components/DamageableComponent.cs b/Content.Shared/Damage/Components/DamageableComponent.cs
index dd0e756c0e..17ad591255 100644
--- a/Content.Shared/Damage/Components/DamageableComponent.cs
+++ b/Content.Shared/Damage/Components/DamageableComponent.cs
@@ -13,6 +13,7 @@ using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
using Robust.Shared.ViewVariables;
+using Content.Shared.Administration.Logs;
namespace Content.Shared.Damage
{
@@ -93,7 +94,11 @@ namespace Content.Shared.Damage
damage.DamageDict.Add(typeID, damageValue);
}
- EntitySystem.Get().TryChangeDamage(OwnerUid, damage);
+ var actual = EntitySystem.Get().TryChangeDamage(OwnerUid, damage);
+
+ // should logging be disabled during rad storms? a lot of entities are going to be damaged.
+ if (actual != null)
+ EntitySystem.Get().Add(LogType.Radiation, $"{Owner} took {actual.Total} radiation damage");
}
// TODO EXPLOSION Remove this.
@@ -114,7 +119,11 @@ namespace Content.Shared.Damage
damage.DamageDict.Add(typeID, damageValue);
}
- EntitySystem.Get().TryChangeDamage(OwnerUid, damage);
+ var actual = EntitySystem.Get().TryChangeDamage(OwnerUid, damage);
+
+ // will logging handle nukes?
+ if (actual != null)
+ EntitySystem.Get().Add(LogType.Explosion, $"{Owner} took {actual.Total} explosion damage");
}
}
diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs
index d757cb4616..ff9c05c425 100644
--- a/Content.Shared/Damage/Systems/DamageableSystem.cs
+++ b/Content.Shared/Damage/Systems/DamageableSystem.cs
@@ -23,7 +23,10 @@ namespace Content.Shared.Damage
SubscribeLocalEvent(DamageableGetState);
}
- protected virtual void SetTotalDamage(DamageableComponent damageable, FixedPoint2 @new)
+ ///
+ /// Update the total damage value and optionally add to admin logs
+ ///
+ protected virtual void SetTotalDamage(DamageableComponent damageable, FixedPoint2 @new, bool logChange)
{
var owner = damageable.Owner;
var old = damageable.TotalDamage;
@@ -33,6 +36,11 @@ namespace Content.Shared.Damage
return;
}
+ damageable.TotalDamage = @new;
+
+ if (!logChange)
+ return;
+
LogType logType;
string type;
FixedPoint2 change;
@@ -52,7 +60,6 @@ namespace Content.Shared.Damage
_logs.Add(logType, $"{owner} {type} {change} damage. Old: {old} | New: {@new}");
- damageable.TotalDamage = @new;
}
///
@@ -103,7 +110,7 @@ namespace Content.Shared.Damage
public void SetDamage(DamageableComponent damageable, DamageSpecifier damage)
{
damageable.Damage = damage;
- DamageChanged(damageable);
+ DamageChanged(damageable, false);
}
///
@@ -113,10 +120,11 @@ namespace Content.Shared.Damage
/// This updates cached damage information, flags the component as dirty, and raises a damage changed event.
/// The damage changed event is used by other systems, such as damage thresholds.
///
- public void DamageChanged(DamageableComponent component, DamageSpecifier? damageDelta = null, bool interruptsDoAfters = true)
+ public void DamageChanged(DamageableComponent component, bool logChange, DamageSpecifier? damageDelta = null,
+ bool interruptsDoAfters = true)
{
component.DamagePerGroup = component.Damage.GetDamagePerGroup();
- SetTotalDamage(component, component.Damage.Total);
+ SetTotalDamage(component, component.Damage.Total, logChange);
component.Dirty();
if (EntityManager.TryGetComponent(component.OwnerUid, out var appearance) && damageDelta != null)
@@ -136,7 +144,8 @@ namespace Content.Shared.Damage
/// Returns a with information about the actual damage changes. This will be
/// null if the user had no applicable components that can take damage.
///
- public DamageSpecifier? TryChangeDamage(EntityUid uid, DamageSpecifier damage, bool ignoreResistances = false, bool interruptsDoAfters = true)
+ public DamageSpecifier? TryChangeDamage(EntityUid uid, DamageSpecifier damage, bool ignoreResistances = false,
+ bool interruptsDoAfters = true, bool logChange = false)
{
if (!EntityManager.TryGetComponent(uid, out var damageable))
{
@@ -185,7 +194,7 @@ namespace Content.Shared.Damage
if (!delta.Empty)
{
- DamageChanged(damageable, delta, interruptsDoAfters);
+ DamageChanged(damageable, logChange, delta, interruptsDoAfters);
}
return delta;
@@ -212,7 +221,7 @@ namespace Content.Shared.Damage
// Setting damage does not count as 'dealing' damage, even if it is set to a larger value, so we pass an
// empty damage delta.
- DamageChanged(component, new DamageSpecifier());
+ DamageChanged(component, false, new DamageSpecifier());
}
private void DamageableGetState(EntityUid uid, DamageableComponent component, ref ComponentGetState args)
@@ -237,7 +246,7 @@ namespace Content.Shared.Damage
if (!delta.Empty)
{
component.Damage = newDamage;
- DamageChanged(component, delta);
+ DamageChanged(component, false, delta);
}
}
}
diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs
index 79c47c13ba..c5e3bf3cba 100644
--- a/Content.Shared/Interaction/SharedInteractionSystem.cs
+++ b/Content.Shared/Interaction/SharedInteractionSystem.cs
@@ -543,18 +543,6 @@ namespace Content.Shared.Interaction
#endregion
#region Throw
- ///
- /// Activates the Throw behavior of an object
- /// Verifies that the user is capable of doing the throw interaction first
- ///
- public bool TryThrowInteraction(IEntity user, IEntity item)
- {
- if (user == null || item == null || !_actionBlockerSystem.CanThrow(user.Uid)) return false;
-
- ThrownInteraction(user, item);
- return true;
- }
-
///
/// Calls Thrown on all components that implement the IThrown interface
/// on an entity that has been thrown.
diff --git a/Content.Shared/Throwing/ThrownItemSystem.cs b/Content.Shared/Throwing/ThrownItemSystem.cs
index a750fe4fa0..3da0b52c10 100644
--- a/Content.Shared/Throwing/ThrownItemSystem.cs
+++ b/Content.Shared/Throwing/ThrownItemSystem.cs
@@ -1,17 +1,12 @@
-using System.Collections.Generic;
-using System.Linq;
using Content.Shared.Administration.Logs;
-using Content.Shared.CCVar;
using Content.Shared.Hands.Components;
using Content.Shared.Physics;
using Content.Shared.Physics.Pull;
-using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Log;
-using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Dynamics;
@@ -128,13 +123,12 @@ namespace Content.Shared.Throwing
return;
}
- var landMsg = new LandEvent {User = thrownItem.Thrower?.Uid};
- RaiseLocalEvent(landing.Uid, landMsg, false);
-
// Assume it's uninteresting if it has no thrower. For now anyway.
if (thrownItem.Thrower is not null)
_adminLogSystem.Add(LogType.Landed, LogImpact.Low, $"{landing} thrown by {thrownItem.Thrower:thrower} landed.");
+ var landMsg = new LandEvent {User = thrownItem.Thrower?.Uid};
+ RaiseLocalEvent(landing.Uid, landMsg, false);
}
///
@@ -142,11 +136,12 @@ namespace Content.Shared.Throwing
///
public void ThrowCollideInteraction(IEntity? user, IPhysBody thrown, IPhysBody target)
{
+ if (user is not null)
+ _adminLogSystem.Add(LogType.ThrowHit, LogImpact.Low,
+ $"{thrown.Owner:thrown} thrown by {user:thrower} hit {target.Owner:target}.");
// TODO: Just pass in the bodies directly
RaiseLocalEvent(target.Owner.Uid, new ThrowHitByEvent(user, thrown.Owner, target.Owner));
RaiseLocalEvent(thrown.Owner.Uid, new ThrowDoHitEvent(user, thrown.Owner, target.Owner));
- if (user is not null)
- _adminLogSystem.Add(LogType.ThrowHit, LogImpact.Low, $"{thrown.Owner:thrown} thrown by {user:thrower} hit {target.Owner:target}.");
}
}
}
diff --git a/Content.Shared/Verbs/SharedVerbSystem.cs b/Content.Shared/Verbs/SharedVerbSystem.cs
index 04a8d1a0d1..3340b97874 100644
--- a/Content.Shared/Verbs/SharedVerbSystem.cs
+++ b/Content.Shared/Verbs/SharedVerbSystem.cs
@@ -73,18 +73,27 @@ namespace Content.Shared.Verbs
}
}
- public void LogVerb(Verb verb, EntityUid user, EntityUid target, bool forced)
+ public void LogVerb(Verb verb, EntityUid userUid, EntityUid targetUid, bool forced)
{
// first get the held item. again.
- EntityUid? used = null;
- if (EntityManager.TryGetComponent(user, out SharedHandsComponent? hands))
+ EntityUid? usedUid = null;
+ if (EntityManager.TryGetComponent(userUid, out SharedHandsComponent? hands))
{
hands.TryGetActiveHeldEntity(out var useEntityd);
- used = useEntityd?.Uid;
- if (used != null && EntityManager.TryGetComponent(used.Value, out HandVirtualItemComponent? pull))
- used = pull.BlockingEntity;
+ usedUid = useEntityd?.Uid;
+ if (usedUid != null && EntityManager.TryGetComponent(usedUid.Value, out HandVirtualItemComponent? pull))
+ usedUid = pull.BlockingEntity;
}
+ // get all the entities
+ if (!EntityManager.TryGetEntity(userUid, out var user) ||
+ !EntityManager.TryGetEntity(targetUid, out var target))
+ return;
+
+ IEntity? used = null;
+ if (usedUid != null)
+ EntityManager.TryGetEntity(usedUid.Value, out used);
+
// then prepare the basic log message body
var verbText = $"{verb.Category?.Text} {verb.Text}".Trim();
var logText = forced