using Content.Server.Administration.Logs;
using Content.Server.Construction.Components;
using Content.Server.Temperature.Components;
-using Content.Server.Temperature.Systems;
using Content.Shared.Construction;
using Content.Shared.Construction.Components;
using Content.Shared.Construction.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Prying.Systems;
using Content.Shared.Radio.EntitySystems;
+using Content.Shared.Temperature;
using Content.Shared.Tools.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Utility;
-using Content.Server.Temperature.Systems;
using Content.Shared.Alert;
using Content.Shared.Atmos;
using Content.Shared.Damage;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float AtmosTemperatureTransferEfficiency = 0.1f;
- [Obsolete("Use system method")]
- public float HeatCapacity
- {
- get
- {
- return IoCManager.Resolve<IEntityManager>().System<TemperatureSystem>().GetHeatCapacity(Owner, this);
- }
- }
-
[DataField, ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier ColdDamage = new();
/// </summary>
/// <remarks>
/// Okay it genuinely reaches this basically immediately for a plasma fire.
- /// </summary>
+ /// </remarks>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 DamageCap = FixedPoint2.New(8);
/// Used to keep track of when damage starts/stops. Useful for logs.
/// </summary>
[DataField]
- public bool TakingDamage = false;
+ public bool TakingDamage;
[DataField]
public ProtoId<AlertPrototype> HotAlert = "Hot";
return (newHeatThreshold, newColdThreshold);
}
}
-
-public sealed class OnTemperatureChangeEvent : EntityEventArgs
-{
- public float CurrentTemperature { get; }
- public float LastTemperature { get; }
- public float TemperatureDelta { get; }
-
- public OnTemperatureChangeEvent(float current, float last, float delta)
- {
- CurrentTemperature = current;
- LastTemperature = last;
- TemperatureDelta = delta;
- }
-}
--- /dev/null
+using Content.Shared.Temperature.Systems;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Temperature.Components;
+
+/// <summary>
+/// This is used for an entity that varies in speed based on current temperature.
+/// </summary>
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedTemperatureSystem)), AutoGenerateComponentState, AutoGenerateComponentPause]
+public sealed partial class TemperatureSpeedComponent : Component
+{
+ /// <summary>
+ /// Pairs of temperature thresholds to applied slowdown values.
+ /// </summary>
+ [DataField]
+ public Dictionary<float, float> Thresholds = new();
+
+ /// <summary>
+ /// The current speed modifier from <see cref="Thresholds"/> we reached.
+ /// Stored and networked so that the client doesn't mispredict temperature
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public float? CurrentSpeedModifier;
+
+ /// <summary>
+ /// The time at which the temperature slowdown is updated.
+ /// </summary>
+ [DataField, AutoNetworkedField, AutoPausedField]
+ public TimeSpan? NextSlowdownUpdate;
+}
--- /dev/null
+using System.Linq;
+using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Systems;
+using Content.Shared.Temperature.Components;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Temperature.Systems;
+
+/// <summary>
+/// This handles predicting temperature based speedup.
+/// </summary>
+public sealed class SharedTemperatureSystem : EntitySystem
+{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
+
+ /// <summary>
+ /// Band-aid for unpredicted atmos. Delays the application for a short period so that laggy clients can get the replicated temperature.
+ /// </summary>
+ private static readonly TimeSpan SlowdownApplicationDelay = TimeSpan.FromSeconds(1f);
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<TemperatureSpeedComponent, OnTemperatureChangeEvent>(OnTemperatureChanged);
+ SubscribeLocalEvent<TemperatureSpeedComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
+ }
+
+ private void OnTemperatureChanged(Entity<TemperatureSpeedComponent> ent, ref OnTemperatureChangeEvent args)
+ {
+ foreach (var (threshold, modifier) in ent.Comp.Thresholds)
+ {
+ if (args.CurrentTemperature < threshold && args.LastTemperature > threshold ||
+ args.CurrentTemperature > threshold && args.LastTemperature < threshold)
+ {
+ ent.Comp.NextSlowdownUpdate = _timing.CurTime + SlowdownApplicationDelay;
+ ent.Comp.CurrentSpeedModifier = modifier;
+ Dirty(ent);
+ break;
+ }
+ }
+
+ var maxThreshold = ent.Comp.Thresholds.Max(p => p.Key);
+ if (args.CurrentTemperature > maxThreshold && args.LastTemperature < maxThreshold)
+ {
+ ent.Comp.NextSlowdownUpdate = _timing.CurTime + SlowdownApplicationDelay;
+ ent.Comp.CurrentSpeedModifier = null;
+ Dirty(ent);
+ }
+ }
+
+ private void OnRefreshMovementSpeedModifiers(Entity<TemperatureSpeedComponent> ent, ref RefreshMovementSpeedModifiersEvent args)
+ {
+ // Don't update speed and mispredict while we're compensating for lag.
+ if (ent.Comp.NextSlowdownUpdate != null || ent.Comp.CurrentSpeedModifier == null)
+ return;
+
+ args.ModifySpeed(ent.Comp.CurrentSpeedModifier.Value, ent.Comp.CurrentSpeedModifier.Value);
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator<TemperatureSpeedComponent, MovementSpeedModifierComponent>();
+ while (query.MoveNext(out var uid, out var temp, out var movement))
+ {
+ if (temp.NextSlowdownUpdate == null)
+ continue;
+
+ if (_timing.CurTime < temp.NextSlowdownUpdate)
+ continue;
+
+ temp.NextSlowdownUpdate = null;
+ _movementSpeedModifier.RefreshMovementSpeedModifiers(uid, movement);
+ Dirty(uid, temp);
+ }
+ }
+}
TemperatureDelta = temperature;
}
}
+
+public sealed class OnTemperatureChangeEvent : EntityEventArgs
+{
+ public readonly float CurrentTemperature;
+ public readonly float LastTemperature;
+ public readonly float TemperatureDelta;
+
+ public OnTemperatureChangeEvent(float current, float last, float delta)
+ {
+ CurrentTemperature = current;
+ LastTemperature = last;
+ TemperatureDelta = delta;
+ }
+}
+
heatDamage:
types:
Heat: 1.5 #per second, scales with temperature & other constants
+ - type: TemperatureSpeed
+ thresholds:
+ 293: 0.8
+ 280: 0.6
+ 260: 0.4
- type: ThermalRegulator
metabolismHeat: 800
radiatedHeat: 100
heatDamage:
types:
Heat : 3 #per second, scales with temperature & other constants
+ - type: TemperatureSpeed
+ thresholds:
+ 289: 0.8
+ 275: 0.6
+ 250: 0.4
- type: Sprite # sprite again because we want different layer ordering
noRot: true
drawdepth: Mobs
heatDamage:
types:
Heat : 1.5 #per second, scales with temperature & other constants
+ - type: TemperatureSpeed
+ thresholds:
+ 301: 0.8
+ 295: 0.6
+ 285: 0.4
- type: Wagging
- type: Inventory
speciesId: reptilian