Only auto-enable internals when necessary (#28248)
* Only auto-enable internals when necessary * Add toxic gas check * Rename Any -> AnyPositive
This commit is contained in:
@@ -106,7 +106,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
if (tile?.Air == null)
|
if (tile?.Air == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tile.Air.CopyFromMutable(combined);
|
tile.Air.CopyFrom(combined);
|
||||||
InvalidateVisuals(ent, tile);
|
InvalidateVisuals(ent, tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public sealed class InternalsSystem : EntitySystem
|
|||||||
[Dependency] private readonly GasTankSystem _gasTank = default!;
|
[Dependency] private readonly GasTankSystem _gasTank = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly RespiratorSystem _respirator = default!;
|
||||||
|
|
||||||
private EntityQuery<InternalsComponent> _internalsQuery;
|
private EntityQuery<InternalsComponent> _internalsQuery;
|
||||||
|
|
||||||
@@ -38,15 +39,30 @@ public sealed class InternalsSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<InternalsComponent, GetVerbsEvent<InteractionVerb>>(OnGetInteractionVerbs);
|
SubscribeLocalEvent<InternalsComponent, GetVerbsEvent<InteractionVerb>>(OnGetInteractionVerbs);
|
||||||
SubscribeLocalEvent<InternalsComponent, InternalsDoAfterEvent>(OnDoAfter);
|
SubscribeLocalEvent<InternalsComponent, InternalsDoAfterEvent>(OnDoAfter);
|
||||||
|
|
||||||
SubscribeLocalEvent<StartingGearEquippedEvent>(OnStartingGear);
|
SubscribeLocalEvent<InternalsComponent, StartingGearEquippedEvent>(OnStartingGear);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStartingGear(ref StartingGearEquippedEvent ev)
|
private void OnStartingGear(EntityUid uid, InternalsComponent component, ref StartingGearEquippedEvent args)
|
||||||
{
|
{
|
||||||
if (!_internalsQuery.TryComp(ev.Entity, out var internals) || internals.BreathToolEntity == null)
|
if (component.BreathToolEntity == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ToggleInternals(ev.Entity, ev.Entity, force: false, internals);
|
if (component.GasTankEntity != null)
|
||||||
|
return; // already connected
|
||||||
|
|
||||||
|
// Can the entity breathe the air it is currently exposed to?
|
||||||
|
if (_respirator.CanMetabolizeInhaledAir(uid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var tank = FindBestGasTank(uid);
|
||||||
|
if (tank == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Could the entity metabolise the air in the linked gas tank?
|
||||||
|
if (!_respirator.CanMetabolizeGas(uid, tank.Value.Comp.Air))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ToggleInternals(uid, uid, force: false, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGetInteractionVerbs(
|
private void OnGetInteractionVerbs(
|
||||||
@@ -243,6 +259,7 @@ public sealed class InternalsSystem : EntitySystem
|
|||||||
public Entity<GasTankComponent>? FindBestGasTank(
|
public Entity<GasTankComponent>? FindBestGasTank(
|
||||||
Entity<HandsComponent?, InventoryComponent?, ContainerManagerComponent?> user)
|
Entity<HandsComponent?, InventoryComponent?, ContainerManagerComponent?> user)
|
||||||
{
|
{
|
||||||
|
// TODO use _respirator.CanMetabolizeGas() to prioritize metabolizable gasses
|
||||||
// Prioritise
|
// Prioritise
|
||||||
// 1. back equipped tanks
|
// 1. back equipped tanks
|
||||||
// 2. exo-slot tanks
|
// 2. exo-slot tanks
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Server.Atmos.EntitySystems;
|
|||||||
using Content.Server.Body.Components;
|
using Content.Server.Body.Components;
|
||||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Clothing;
|
using Content.Shared.Clothing;
|
||||||
using Content.Shared.Inventory.Events;
|
using Content.Shared.Inventory.Events;
|
||||||
|
|
||||||
@@ -77,23 +78,32 @@ public sealed class LungSystem : EntitySystem
|
|||||||
if (!_solutionContainerSystem.ResolveSolution(uid, lung.SolutionName, ref lung.Solution, out var solution))
|
if (!_solutionContainerSystem.ResolveSolution(uid, lung.SolutionName, ref lung.Solution, out var solution))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var gas in Enum.GetValues<Gas>())
|
GasToReagent(lung.Air, solution);
|
||||||
|
_solutionContainerSystem.UpdateChemicals(lung.Solution.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GasToReagent(GasMixture gas, Solution solution)
|
||||||
|
{
|
||||||
|
foreach (var gasId in Enum.GetValues<Gas>())
|
||||||
{
|
{
|
||||||
var i = (int) gas;
|
var i = (int) gasId;
|
||||||
var moles = lung.Air[i];
|
var moles = gas[i];
|
||||||
if (moles <= 0)
|
if (moles <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var reagent = _atmosphereSystem.GasReagents[i];
|
var reagent = _atmosphereSystem.GasReagents[i];
|
||||||
if (reagent is null) continue;
|
if (reagent is null)
|
||||||
|
continue;
|
||||||
|
|
||||||
var amount = moles * Atmospherics.BreathMolesToReagentMultiplier;
|
var amount = moles * Atmospherics.BreathMolesToReagentMultiplier;
|
||||||
solution.AddReagent(reagent, amount);
|
solution.AddReagent(reagent, amount);
|
||||||
|
|
||||||
// We don't remove the gas from the lung mix,
|
|
||||||
// that's the responsibility of whatever gas is being metabolized.
|
|
||||||
// Most things will just want to exhale again.
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_solutionContainerSystem.UpdateChemicals(lung.Solution.Value);
|
public Solution GasToReagent(GasMixture gas)
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
GasToReagent(gas, solution);
|
||||||
|
return solution;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Atmos;
|
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.Body.Components;
|
using Content.Server.Body.Components;
|
||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||||
|
using Content.Server.Chemistry.ReagentEffectConditions;
|
||||||
|
using Content.Server.Chemistry.ReagentEffects;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
|
using Content.Shared.Body.Prototypes;
|
||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Server.Body.Systems;
|
namespace Content.Server.Body.Systems;
|
||||||
@@ -26,9 +31,12 @@ public sealed class RespiratorSystem : EntitySystem
|
|||||||
[Dependency] private readonly DamageableSystem _damageableSys = default!;
|
[Dependency] private readonly DamageableSystem _damageableSys = default!;
|
||||||
[Dependency] private readonly LungSystem _lungSystem = default!;
|
[Dependency] private readonly LungSystem _lungSystem = default!;
|
||||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||||
[Dependency] private readonly ChatSystem _chat = default!;
|
[Dependency] private readonly ChatSystem _chat = default!;
|
||||||
|
|
||||||
|
private static readonly ProtoId<MetabolismGroupPrototype> GasId = new("Gas");
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -109,7 +117,7 @@ public sealed class RespiratorSystem : EntitySystem
|
|||||||
|
|
||||||
// Inhale gas
|
// Inhale gas
|
||||||
var ev = new InhaleLocationEvent();
|
var ev = new InhaleLocationEvent();
|
||||||
RaiseLocalEvent(uid, ref ev, broadcast: false);
|
RaiseLocalEvent(uid, ref ev);
|
||||||
|
|
||||||
ev.Gas ??= _atmosSys.GetContainingMixture(uid, excite: true);
|
ev.Gas ??= _atmosSys.GetContainingMixture(uid, excite: true);
|
||||||
|
|
||||||
@@ -164,6 +172,112 @@ public sealed class RespiratorSystem : EntitySystem
|
|||||||
_atmosSys.Merge(ev.Gas, outGas);
|
_atmosSys.Merge(ev.Gas, outGas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check whether or not an entity can metabolize inhaled air without suffocating or taking damage (i.e., no toxic
|
||||||
|
/// gasses).
|
||||||
|
/// </summary>
|
||||||
|
public bool CanMetabolizeInhaledAir(Entity<RespiratorComponent?> ent)
|
||||||
|
{
|
||||||
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var ev = new InhaleLocationEvent();
|
||||||
|
RaiseLocalEvent(ent, ref ev);
|
||||||
|
|
||||||
|
var gas = ev.Gas ?? _atmosSys.GetContainingMixture(ent.Owner);
|
||||||
|
if (gas == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return CanMetabolizeGas(ent, gas);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check whether or not an entity can metabolize the given gas mixture without suffocating or taking damage
|
||||||
|
/// (i.e., no toxic gasses).
|
||||||
|
/// </summary>
|
||||||
|
public bool CanMetabolizeGas(Entity<RespiratorComponent?> ent, GasMixture gas)
|
||||||
|
{
|
||||||
|
if (!Resolve(ent, ref ent.Comp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var organs = _bodySystem.GetBodyOrganComponents<LungComponent>(ent);
|
||||||
|
if (organs.Count == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gas = new GasMixture(gas);
|
||||||
|
var lungRatio = 1.0f / organs.Count;
|
||||||
|
gas.Multiply(MathF.Min(lungRatio * gas.Volume/Atmospherics.BreathVolume, lungRatio));
|
||||||
|
var solution = _lungSystem.GasToReagent(gas);
|
||||||
|
|
||||||
|
float saturation = 0;
|
||||||
|
foreach (var organ in organs)
|
||||||
|
{
|
||||||
|
saturation += GetSaturation(solution, organ.Comp.Owner, out var toxic);
|
||||||
|
if (toxic)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return saturation > ent.Comp.UpdateInterval.TotalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the amount of saturation that would be generated if the lung were to metabolize the given solution.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This assumes the metabolism rate is unbounded, which generally should be the case for lungs, otherwise we get
|
||||||
|
/// back to the old pulmonary edema bug.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="solution">The reagents to metabolize</param>
|
||||||
|
/// <param name="lung">The entity doing the metabolizing</param>
|
||||||
|
/// <param name="toxic">Whether or not any of the reagents would deal damage to the entity</param>
|
||||||
|
private float GetSaturation(Solution solution, Entity<MetabolizerComponent?> lung, out bool toxic)
|
||||||
|
{
|
||||||
|
toxic = false;
|
||||||
|
if (!Resolve(lung, ref lung.Comp))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (lung.Comp.MetabolismGroups == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
float saturation = 0;
|
||||||
|
foreach (var (id, quantity) in solution.Contents)
|
||||||
|
{
|
||||||
|
var reagent = _protoMan.Index<ReagentPrototype>(id.Prototype);
|
||||||
|
if (reagent.Metabolisms == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!reagent.Metabolisms.TryGetValue(GasId, out var entry))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var effect in entry.Effects)
|
||||||
|
{
|
||||||
|
if (effect is HealthChange health)
|
||||||
|
toxic |= CanMetabolize(health) && health.Damage.AnyPositive();
|
||||||
|
else if (effect is Oxygenate oxy && CanMetabolize(oxy))
|
||||||
|
saturation += oxy.Factor * quantity.Float();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO generalize condition checks
|
||||||
|
// this is pretty janky, but I just want to bodge a method that checks if an entity can breathe a gas mixture
|
||||||
|
// Applying actual reaction effects require a full ReagentEffectArgs struct.
|
||||||
|
bool CanMetabolize(ReagentEffect effect)
|
||||||
|
{
|
||||||
|
if (effect.Conditions == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
foreach (var cond in effect.Conditions)
|
||||||
|
{
|
||||||
|
if (cond is OrganType organ && !organ.Condition(lung, EntityManager))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return saturation;
|
||||||
|
}
|
||||||
|
|
||||||
private void TakeSuffocationDamage(Entity<RespiratorComponent> ent)
|
private void TakeSuffocationDamage(Entity<RespiratorComponent> ent)
|
||||||
{
|
{
|
||||||
if (ent.Comp.SuffocationCycles == 2)
|
if (ent.Comp.SuffocationCycles == 2)
|
||||||
|
|||||||
@@ -25,9 +25,15 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
|
|||||||
if (args.OrganEntity == null)
|
if (args.OrganEntity == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (args.EntityManager.TryGetComponent<MetabolizerComponent>(args.OrganEntity.Value, out var metabolizer)
|
return Condition(args.OrganEntity.Value, args.EntityManager);
|
||||||
&& metabolizer.MetabolizerTypes != null
|
}
|
||||||
&& metabolizer.MetabolizerTypes.Contains(Type))
|
|
||||||
|
public bool Condition(Entity<MetabolizerComponent?> metabolizer, IEntityManager entMan)
|
||||||
|
{
|
||||||
|
metabolizer.Comp ??= entMan.GetComponentOrNull<MetabolizerComponent>(metabolizer.Owner);
|
||||||
|
if (metabolizer.Comp != null
|
||||||
|
&& metabolizer.Comp.MetabolizerTypes != null
|
||||||
|
&& metabolizer.Comp.MetabolizerTypes.Contains(Type))
|
||||||
return ShouldHave;
|
return ShouldHave;
|
||||||
return !ShouldHave;
|
return !ShouldHave;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace Content.Server.Damage.Systems
|
|||||||
private void OnAttemptPacifiedThrow(Entity<DamageOnLandComponent> ent, ref AttemptPacifiedThrowEvent args)
|
private void OnAttemptPacifiedThrow(Entity<DamageOnLandComponent> ent, ref AttemptPacifiedThrowEvent args)
|
||||||
{
|
{
|
||||||
// Allow healing projectiles, forbid any that do damage:
|
// Allow healing projectiles, forbid any that do damage:
|
||||||
if (ent.Comp.Damage.Any())
|
if (ent.Comp.Damage.AnyPositive())
|
||||||
{
|
{
|
||||||
args.Cancel("pacified-cannot-throw");
|
args.Cancel("pacified-cannot-throw");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
|||||||
if (!electrified.OnAttacked)
|
if (!electrified.OnAttacked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_meleeWeapon.GetDamage(args.Used, args.User).Any())
|
if (_meleeWeapon.GetDamage(args.Used, args.User).Empty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TryDoElectrifiedAct(uid, args.User, 1, electrified);
|
TryDoElectrifiedAct(uid, args.User, 1, electrified);
|
||||||
@@ -183,7 +183,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
|||||||
if (!component.CurrentLit || args.Used != args.User)
|
if (!component.CurrentLit || args.Used != args.User)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_meleeWeapon.GetDamage(args.Used, args.User).Any())
|
if (_meleeWeapon.GetDamage(args.Used, args.User).Empty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DoCommonElectrocution(args.User, uid, component.UnarmedHitShock, component.UnarmedHitStun, false);
|
DoCommonElectrocution(args.User, uid, component.UnarmedHitShock, component.UnarmedHitStun, false);
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ public sealed partial class ExplosionSystem
|
|||||||
|
|
||||||
// don't raise BeforeExplodeEvent if the entity is completely immune to explosions
|
// don't raise BeforeExplodeEvent if the entity is completely immune to explosions
|
||||||
var thisDamage = GetDamage(uid, prototype, originalDamage);
|
var thisDamage = GetDamage(uid, prototype, originalDamage);
|
||||||
if (!thisDamage.Any())
|
if (thisDamage.Empty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_toDamage.Add((uid, thisDamage));
|
_toDamage.Add((uid, thisDamage));
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public sealed class ProjectileSystem : SharedProjectileSystem
|
|||||||
|
|
||||||
if (modifiedDamage is not null && EntityManager.EntityExists(component.Shooter))
|
if (modifiedDamage is not null && EntityManager.EntityExists(component.Shooter))
|
||||||
{
|
{
|
||||||
if (modifiedDamage.Any() && !deleted)
|
if (modifiedDamage.AnyPositive() && !deleted)
|
||||||
{
|
{
|
||||||
_color.RaiseEffect(Color.Red, new List<EntityUid> { target }, Filter.Pvs(target, entityManager: EntityManager));
|
_color.RaiseEffect(Color.Red, new List<EntityUid> { target }, Filter.Pvs(target, entityManager: EntityManager));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
var gearEquippedEv = new StartingGearEquippedEvent(entity.Value);
|
var gearEquippedEv = new StartingGearEquippedEvent(entity.Value);
|
||||||
RaiseLocalEvent(entity.Value, ref gearEquippedEv, true);
|
RaiseLocalEvent(entity.Value, ref gearEquippedEv);
|
||||||
|
|
||||||
if (profile != null)
|
if (profile != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ public sealed class BluespaceLockerSystem : EntitySystem
|
|||||||
// Move contained air
|
// Move contained air
|
||||||
if (component.BehaviorProperties.TransportGas)
|
if (component.BehaviorProperties.TransportGas)
|
||||||
{
|
{
|
||||||
entityStorageComponent.Air.CopyFromMutable(target.Value.storageComponent.Air);
|
entityStorageComponent.Air.CopyFrom(target.Value.storageComponent.Air);
|
||||||
target.Value.storageComponent.Air.Clear();
|
target.Value.storageComponent.Air.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +326,7 @@ public sealed class BluespaceLockerSystem : EntitySystem
|
|||||||
// Move contained air
|
// Move contained air
|
||||||
if (component.BehaviorProperties.TransportGas)
|
if (component.BehaviorProperties.TransportGas)
|
||||||
{
|
{
|
||||||
target.Value.storageComponent.Air.CopyFromMutable(entityStorageComponent.Air);
|
target.Value.storageComponent.Air.CopyFrom(entityStorageComponent.Air);
|
||||||
entityStorageComponent.Air.Clear();
|
entityStorageComponent.Air.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ public sealed partial class GunSystem : SharedGunSystem
|
|||||||
{
|
{
|
||||||
if (!Deleted(hitEntity))
|
if (!Deleted(hitEntity))
|
||||||
{
|
{
|
||||||
if (dmg.Any())
|
if (dmg.AnyPositive())
|
||||||
{
|
{
|
||||||
_color.RaiseEffect(Color.Red, new List<EntityUid>() { hitEntity }, Filter.Pvs(hitEntity, entityManager: EntityManager));
|
_color.RaiseEffect(Color.Red, new List<EntityUid>() { hitEntity }, Filter.Pvs(hitEntity, entityManager: EntityManager));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,11 @@ namespace Content.Shared.Atmos
|
|||||||
Volume = volume;
|
Volume = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GasMixture(GasMixture toClone)
|
||||||
|
{
|
||||||
|
CopyFrom(toClone);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void MarkImmutable()
|
public void MarkImmutable()
|
||||||
{
|
{
|
||||||
@@ -197,9 +202,12 @@ namespace Content.Shared.Atmos
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void CopyFromMutable(GasMixture sample)
|
public void CopyFrom(GasMixture sample)
|
||||||
{
|
{
|
||||||
if (Immutable) return;
|
if (Immutable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Volume = sample.Volume;
|
||||||
sample.Moles.CopyTo(Moles, 0);
|
sample.Moles.CopyTo(Moles, 0);
|
||||||
Temperature = sample.Temperature;
|
Temperature = sample.Temperature;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace Content.Shared.Damage
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Note that this being zero does not mean this damage has no effect. Healing in one type may cancel damage
|
/// Note that this being zero does not mean this damage has no effect. Healing in one type may cancel damage
|
||||||
/// in another. Consider using <see cref="Any()"/> or <see cref="Empty"/> instead.
|
/// in another. Consider using <see cref="AnyPositive"/> or <see cref="Empty"/> instead.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public FixedPoint2 GetTotal()
|
public FixedPoint2 GetTotal()
|
||||||
{
|
{
|
||||||
@@ -60,7 +60,7 @@ namespace Content.Shared.Damage
|
|||||||
/// Differs from <see cref="Empty"/> as a damage specifier might contain entries with zeroes.
|
/// Differs from <see cref="Empty"/> as a damage specifier might contain entries with zeroes.
|
||||||
/// This also returns false if the specifier only contains negative values.
|
/// This also returns false if the specifier only contains negative values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Any()
|
public bool AnyPositive()
|
||||||
{
|
{
|
||||||
foreach (var value in DamageDict.Values)
|
foreach (var value in DamageDict.Values)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ public abstract class SharedStationSpawningSystem : EntitySystem
|
|||||||
if (raiseEvent)
|
if (raiseEvent)
|
||||||
{
|
{
|
||||||
var ev = new StartingGearEquippedEvent(entity);
|
var ev = new StartingGearEquippedEvent(entity);
|
||||||
RaiseLocalEvent(entity, ref ev, true);
|
RaiseLocalEvent(entity, ref ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -499,7 +499,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
|
|||||||
var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList);
|
var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList);
|
||||||
var damageResult = Damageable.TryChangeDamage(target, modifiedDamage, origin:user);
|
var damageResult = Damageable.TryChangeDamage(target, modifiedDamage, origin:user);
|
||||||
|
|
||||||
if (damageResult != null && damageResult.Any())
|
if (damageResult is {Empty: false})
|
||||||
{
|
{
|
||||||
// If the target has stamina and is taking blunt damage, they should also take stamina damage based on their blunt to stamina factor
|
// If the target has stamina and is taking blunt damage, they should also take stamina damage based on their blunt to stamina factor
|
||||||
if (damageResult.DamageDict.TryGetValue("Blunt", out var bluntDamage))
|
if (damageResult.DamageDict.TryGetValue("Blunt", out var bluntDamage))
|
||||||
|
|||||||
Reference in New Issue
Block a user