Merge branch 'master' into replace-sounds-with-sound-specifier
This commit is contained in:
@@ -4,7 +4,7 @@ using Content.Shared.Emoting;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Metabolism.Events;
|
||||
using Content.Shared.Body.Metabolism;
|
||||
using Content.Shared.Movement;
|
||||
using Content.Shared.Speech;
|
||||
using Content.Shared.Throwing;
|
||||
|
||||
@@ -4,31 +4,37 @@ using Robust.Shared.Serialization;
|
||||
namespace Content.Shared.Atmos.Piping
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public enum OutletInjectorVisuals
|
||||
public enum OutletInjectorVisuals : byte
|
||||
{
|
||||
Enabled,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum PassiveVentVisuals
|
||||
public enum PassiveVentVisuals : byte
|
||||
{
|
||||
Enabled,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum VentScrubberVisuals
|
||||
public enum VentScrubberVisuals : byte
|
||||
{
|
||||
Enabled,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum ThermoMachineVisuals
|
||||
public enum ThermoMachineVisuals : byte
|
||||
{
|
||||
Enabled,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum PressurePumpVisuals
|
||||
public enum PressurePumpVisuals : byte
|
||||
{
|
||||
Enabled,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum FilterVisuals : byte
|
||||
{
|
||||
Enabled,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.Metabolism.Events
|
||||
namespace Content.Shared.Body.Metabolism
|
||||
{
|
||||
public class ShiverAttemptEvent : CancellableEntityEventArgs
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.Metabolism.Events
|
||||
namespace Content.Shared.Body.Metabolism
|
||||
{
|
||||
public class SweatAttemptEvent : CancellableEntityEventArgs
|
||||
{
|
||||
@@ -55,6 +55,19 @@ namespace Content.Shared.CCVar
|
||||
public static readonly CVarDef<string>
|
||||
GameMap = CVarDef.Create("game.map", "Maps/saltern.yml", CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// Whether a random position offset will be applied to the station on roundstart.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> StationOffset =
|
||||
CVarDef.Create("game.station_offset", true);
|
||||
|
||||
/// <summary>
|
||||
/// When the default blueprint is loaded what is the maximum amount it can be offset from 0,0.
|
||||
/// Does nothing without <see cref="StationOffset"/> as true.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> MaxStationOffset =
|
||||
CVarDef.Create("game.maxstationoffset", 1000.0f);
|
||||
|
||||
/// <summary>
|
||||
/// When enabled, guests will be assigned permanent UIDs and will have their preferences stored.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,47 +1,90 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Body.Part;
|
||||
|
||||
namespace Content.Shared.CharacterAppearance
|
||||
{
|
||||
public static class HumanoidVisualLayersExtension
|
||||
{
|
||||
public static HumanoidVisualLayers? ToHumanoidLayer(this SharedBodyPartComponent part)
|
||||
public static IEnumerable<HumanoidVisualLayers> ToHumanoidLayers(this SharedBodyPartComponent part)
|
||||
{
|
||||
return part.PartType switch
|
||||
switch (part.PartType)
|
||||
{
|
||||
BodyPartType.Other => null,
|
||||
BodyPartType.Torso => HumanoidVisualLayers.Chest,
|
||||
BodyPartType.Head => HumanoidVisualLayers.Head,
|
||||
BodyPartType.Arm => part.Symmetry switch
|
||||
{
|
||||
BodyPartSymmetry.None => null,
|
||||
BodyPartSymmetry.Left => HumanoidVisualLayers.LArm,
|
||||
BodyPartSymmetry.Right => HumanoidVisualLayers.RArm,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
BodyPartType.Hand => part.Symmetry switch
|
||||
{
|
||||
BodyPartSymmetry.None => null,
|
||||
BodyPartSymmetry.Left => HumanoidVisualLayers.LHand,
|
||||
BodyPartSymmetry.Right => HumanoidVisualLayers.RHand,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
BodyPartType.Leg => part.Symmetry switch
|
||||
{
|
||||
BodyPartSymmetry.None => null,
|
||||
BodyPartSymmetry.Left => HumanoidVisualLayers.LLeg,
|
||||
BodyPartSymmetry.Right => HumanoidVisualLayers.RLeg,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
BodyPartType.Foot => part.Symmetry switch
|
||||
{
|
||||
BodyPartSymmetry.None => null,
|
||||
BodyPartSymmetry.Left => HumanoidVisualLayers.LFoot,
|
||||
BodyPartSymmetry.Right => HumanoidVisualLayers.RFoot,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
case BodyPartType.Other:
|
||||
yield break;
|
||||
case BodyPartType.Torso:
|
||||
yield return HumanoidVisualLayers.Chest;
|
||||
break;
|
||||
case BodyPartType.Head:
|
||||
yield return HumanoidVisualLayers.Head;
|
||||
yield return HumanoidVisualLayers.Eyes;
|
||||
yield return HumanoidVisualLayers.FacialHair;
|
||||
yield return HumanoidVisualLayers.Hair;
|
||||
yield return HumanoidVisualLayers.StencilMask;
|
||||
break;
|
||||
case BodyPartType.Arm:
|
||||
switch (part.Symmetry)
|
||||
{
|
||||
case BodyPartSymmetry.None:
|
||||
yield break;
|
||||
case BodyPartSymmetry.Left:
|
||||
yield return HumanoidVisualLayers.LArm;
|
||||
break;
|
||||
case BodyPartSymmetry.Right:
|
||||
yield return HumanoidVisualLayers.RArm;
|
||||
break;
|
||||
default:
|
||||
yield break;
|
||||
}
|
||||
yield break;
|
||||
case BodyPartType.Hand:
|
||||
switch (part.Symmetry)
|
||||
{
|
||||
case BodyPartSymmetry.None:
|
||||
yield break;
|
||||
case BodyPartSymmetry.Left:
|
||||
yield return HumanoidVisualLayers.LHand;
|
||||
break;
|
||||
case BodyPartSymmetry.Right:
|
||||
yield return HumanoidVisualLayers.RHand;
|
||||
break;
|
||||
default:
|
||||
yield break;
|
||||
}
|
||||
yield break;
|
||||
case BodyPartType.Leg:
|
||||
switch (part.Symmetry)
|
||||
{
|
||||
case BodyPartSymmetry.None:
|
||||
yield break;
|
||||
case BodyPartSymmetry.Left:
|
||||
yield return HumanoidVisualLayers.LLeg;
|
||||
break;
|
||||
case BodyPartSymmetry.Right:
|
||||
yield return HumanoidVisualLayers.RLeg;
|
||||
break;
|
||||
default:
|
||||
yield break;
|
||||
}
|
||||
yield break;
|
||||
case BodyPartType.Foot:
|
||||
switch (part.Symmetry)
|
||||
{
|
||||
case BodyPartSymmetry.None:
|
||||
yield break;
|
||||
case BodyPartSymmetry.Left:
|
||||
yield return HumanoidVisualLayers.LFoot;
|
||||
break;
|
||||
case BodyPartSymmetry.Right:
|
||||
yield return HumanoidVisualLayers.RFoot;
|
||||
break;
|
||||
default:
|
||||
yield break;
|
||||
}
|
||||
yield break;
|
||||
default:
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using Content.Shared.Movement.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using System;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Shared.Chemistry.Components
|
||||
{
|
||||
//TODO: refactor movement modifier component because this is a pretty poor solution
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent]
|
||||
public sealed class MovespeedModifierMetabolismComponent : Component, IMoveSpeedModifier
|
||||
{
|
||||
[ViewVariables]
|
||||
public override string Name => "MovespeedModifierMetabolism";
|
||||
|
||||
[ViewVariables]
|
||||
public float WalkSpeedModifier { get; set; }
|
||||
|
||||
[ViewVariables]
|
||||
public float SprintSpeedModifier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the current modifier is expected to end.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public TimeSpan ModifierTimer { get; set; } = TimeSpan.Zero;
|
||||
|
||||
public override ComponentState GetComponentState(ICommonSession player)
|
||||
{
|
||||
return new MovespeedModifierMetabolismComponentState(WalkSpeedModifier, SprintSpeedModifier, ModifierTimer);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class MovespeedModifierMetabolismComponentState : ComponentState
|
||||
{
|
||||
public float WalkSpeedModifier { get; }
|
||||
public float SprintSpeedModifier { get; }
|
||||
public TimeSpan ModifierTimer { get; }
|
||||
|
||||
public MovespeedModifierMetabolismComponentState(float walkSpeedModifier, float sprintSpeedModifier, TimeSpan modifierTimer)
|
||||
{
|
||||
WalkSpeedModifier = walkSpeedModifier;
|
||||
SprintSpeedModifier = sprintSpeedModifier;
|
||||
ModifierTimer = modifierTimer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Movement.Components;
|
||||
using static Content.Shared.Chemistry.Components.MovespeedModifierMetabolismComponent;
|
||||
|
||||
namespace Content.Shared.Chemistry
|
||||
{
|
||||
public class MetabolismMovespeedModifierSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
private readonly List<MovespeedModifierMetabolismComponent> _components = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<MovespeedModifierMetabolismComponent, ComponentHandleState>(OnMovespeedHandleState);
|
||||
SubscribeLocalEvent<MovespeedModifierMetabolismComponent, ComponentStartup>(AddComponent);
|
||||
}
|
||||
|
||||
private void OnMovespeedHandleState(EntityUid uid, MovespeedModifierMetabolismComponent component, ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not MovespeedModifierMetabolismComponentState cast)
|
||||
return;
|
||||
|
||||
if (ComponentManager.TryGetComponent<MovementSpeedModifierComponent>(uid, out var modifier) &&
|
||||
(!component.WalkSpeedModifier.Equals(cast.WalkSpeedModifier) ||
|
||||
!component.SprintSpeedModifier.Equals(cast.SprintSpeedModifier)))
|
||||
{
|
||||
modifier.RefreshMovementSpeedModifiers();
|
||||
}
|
||||
|
||||
component.WalkSpeedModifier = cast.WalkSpeedModifier;
|
||||
component.SprintSpeedModifier = cast.SprintSpeedModifier;
|
||||
component.ModifierTimer = cast.ModifierTimer;
|
||||
|
||||
}
|
||||
private void AddComponent(EntityUid uid, MovespeedModifierMetabolismComponent component, ComponentStartup args)
|
||||
{
|
||||
_components.Add(component);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var currentTime = _gameTiming.CurTime;
|
||||
|
||||
for (var i = _components.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var component = _components[i];
|
||||
|
||||
if (component.Deleted)
|
||||
{
|
||||
_components.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (component.ModifierTimer > currentTime) continue;
|
||||
|
||||
_components.RemoveAt(i);
|
||||
ComponentManager.RemoveComponent<MovespeedModifierMetabolismComponent>(component.Owner.Uid);
|
||||
|
||||
if (component.Owner.TryGetComponent(out MovementSpeedModifierComponent? modifier))
|
||||
{
|
||||
modifier.RefreshMovementSpeedModifiers();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Chemistry.Metabolizable
|
||||
{
|
||||
/// <summary>
|
||||
/// Default metabolization for reagents. Returns the amount of reagents metabolized without applying effects.
|
||||
/// Metabolizes reagents at a constant rate, limited by how much is available. Other classes are derived from
|
||||
/// this class, so that they do not need their own metabolization quantity calculation.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public class DefaultMetabolizable : IMetabolizable
|
||||
{
|
||||
/// <summary>
|
||||
/// Rate of metabolism in units / second
|
||||
/// </summary>
|
||||
[DataField("rate")] public ReagentUnit MetabolismRate { get; set; } = ReagentUnit.New(1);
|
||||
|
||||
public virtual ReagentUnit Metabolize(IEntity solutionEntity, string reagentId, float tickTime, ReagentUnit availableReagent)
|
||||
{
|
||||
|
||||
// How much reagent should we metabolize
|
||||
// The default behaviour is to metabolize at a constant rate, independent of the quantity of reagents.
|
||||
var amountMetabolized = MetabolismRate * tickTime;
|
||||
|
||||
// is that much reagent actually available?
|
||||
if (availableReagent < amountMetabolized)
|
||||
{
|
||||
return availableReagent;
|
||||
}
|
||||
|
||||
return amountMetabolized;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.Chemistry.Metabolizable
|
||||
{
|
||||
/// <summary>
|
||||
/// Metabolism behavior for a reagent.
|
||||
/// </summary>
|
||||
public interface IMetabolizable
|
||||
{
|
||||
/// <summary>
|
||||
/// Metabolize the attached reagent. Return the amount of reagent to be removed from the solution.
|
||||
/// You shouldn't remove the reagent yourself to avoid invalidating the iterator of the metabolism
|
||||
/// organ that is processing it's reagents.
|
||||
/// </summary>
|
||||
/// <param name="solutionEntity">The entity containing the solution.</param>
|
||||
/// <param name="reagentId">The reagent id</param>
|
||||
/// <param name="tickTime">The time since the last metabolism tick in seconds.</param>
|
||||
/// <param name="availableReagent">Reagent available to be metabolized.</param>
|
||||
/// <returns>The amount of reagent to be removed. The metabolizing organ should handle removing the reagent.</returns>
|
||||
ReagentUnit Metabolize(IEntity solutionEntity, string reagentId, float tickTime, ReagentUnit availableReagent);
|
||||
}
|
||||
}
|
||||
23
Content.Shared/Chemistry/Reagent/ReagentEffect.cs
Normal file
23
Content.Shared/Chemistry/Reagent/ReagentEffect.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Chemistry.Reagent
|
||||
{
|
||||
/// <summary>
|
||||
/// Reagent effects describe behavior that occurs when a reagent is ingested and metabolized by some
|
||||
/// organ. They only trigger when their conditions (<see cref="ReagentEffectCondition"/>
|
||||
/// </summary>
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract class ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of conditions required for the effect to activate. Not required.
|
||||
/// </summary>
|
||||
[DataField("conditions")]
|
||||
public ReagentEffectCondition[]? Conditions;
|
||||
|
||||
public abstract void Metabolize(IEntity solutionEntity, Solution.Solution.ReagentQuantity amount);
|
||||
}
|
||||
}
|
||||
13
Content.Shared/Chemistry/Reagent/ReagentEffectCondition.cs
Normal file
13
Content.Shared/Chemistry/Reagent/ReagentEffectCondition.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Chemistry.Reagent
|
||||
{
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract class ReagentEffectCondition
|
||||
{
|
||||
public abstract bool Condition(IEntity solutionEntity, Solution.Solution.ReagentQuantity reagent);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Botany;
|
||||
using Content.Shared.Chemistry.Metabolizable;
|
||||
using Content.Shared.Chemistry.Reaction;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
@@ -16,9 +15,6 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
[DataDefinition]
|
||||
public class ReagentPrototype : IPrototype
|
||||
{
|
||||
[DataField("metabolism", serverOnly: true)]
|
||||
private readonly List<IMetabolizable> _metabolism = new() {new DefaultMetabolizable()};
|
||||
|
||||
[DataField("tileReactions", serverOnly: true)]
|
||||
private readonly List<ITileReaction> _tileReactions = new(0);
|
||||
|
||||
@@ -60,7 +56,6 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
public string SpriteReplacementPath { get; } = string.Empty;
|
||||
|
||||
//List of metabolism effects this reagent has, should really only be used server-side.
|
||||
public IReadOnlyList<IMetabolizable> Metabolism => _metabolism;
|
||||
public IReadOnlyList<ITileReaction> TileReactions => _tileReactions;
|
||||
public IReadOnlyList<IPlantMetabolizable> PlantMetabolism => _plantMetabolism;
|
||||
|
||||
|
||||
@@ -115,6 +115,27 @@ namespace Content.Shared.Chemistry.Solution
|
||||
TotalVolume += quantity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scales the amount of solution.
|
||||
/// </summary>
|
||||
/// <param name="scale">The scalar to modify the solution by.</param>
|
||||
public void ScaleSolution(float scale)
|
||||
{
|
||||
if (scale == 1) return;
|
||||
var tempContents = new List<ReagentQuantity>(_contents);
|
||||
foreach(ReagentQuantity current in tempContents)
|
||||
{
|
||||
if(scale > 1)
|
||||
{
|
||||
AddReagent(current.ReagentId, current.Quantity * scale - current.Quantity);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveReagent(current.ReagentId, current.Quantity - current.Quantity * scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of a single reagent inside the solution.
|
||||
/// </summary>
|
||||
|
||||
@@ -22,6 +22,9 @@ namespace Content.Shared.Doors
|
||||
[ComponentDependency]
|
||||
protected readonly IPhysBody? PhysicsComponent = null;
|
||||
|
||||
[Dependency]
|
||||
protected readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
[ViewVariables]
|
||||
private DoorState _state = DoorState.Closed;
|
||||
/// <summary>
|
||||
|
||||
@@ -16,8 +16,9 @@ namespace Content.Shared.Ghost
|
||||
public override string Name => "Ghost";
|
||||
|
||||
/// <summary>
|
||||
/// Changed by <see cref="GhostChangeCanReturnToBodyEvent"/>
|
||||
/// Changed by <see cref="SharedGhostSystem.SetCanReturnToBody"/>
|
||||
/// </summary>
|
||||
// TODO MIRROR change this to use friend classes when thats merged
|
||||
[DataField("canReturnToBody")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool CanReturnToBody { get; set; }
|
||||
|
||||
@@ -10,36 +10,20 @@ namespace Content.Shared.Ghost
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SharedGhostComponent, GhostChangeCanReturnToBodyEvent>(OnGhostChangeCanReturnToBody);
|
||||
}
|
||||
|
||||
private void OnGhostChangeCanReturnToBody(EntityUid uid, SharedGhostComponent component, GhostChangeCanReturnToBodyEvent args)
|
||||
public void SetCanReturnToBody(SharedGhostComponent component, bool canReturn)
|
||||
{
|
||||
if (component.CanReturnToBody == args.CanReturnToBody)
|
||||
if (component.CanReturnToBody == canReturn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
component.CanReturnToBody = args.CanReturnToBody;
|
||||
component.CanReturnToBody = canReturn;
|
||||
component.Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised to change the value of <see cref="SharedGhostComponent.CanReturnToBody"/>
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public class GhostChangeCanReturnToBodyEvent : EntityEventArgs
|
||||
{
|
||||
public GhostChangeCanReturnToBodyEvent(bool canReturnToBody)
|
||||
{
|
||||
CanReturnToBody = canReturnToBody;
|
||||
}
|
||||
|
||||
public bool CanReturnToBody { get; }
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class GhostWarpsRequestEvent : EntityEventArgs
|
||||
{
|
||||
|
||||
@@ -924,12 +924,12 @@ namespace Content.Shared.Hands.Components
|
||||
{
|
||||
public EntityUid EntityUid { get; }
|
||||
public EntityCoordinates InitialPosition { get; }
|
||||
public Vector2 PickupDirection { get; }
|
||||
public Vector2 FinalPosition { get; }
|
||||
|
||||
public PickupAnimationMessage(EntityUid entityUid, Vector2 pickupDirection, EntityCoordinates initialPosition)
|
||||
public PickupAnimationMessage(EntityUid entityUid, Vector2 finalPosition, EntityCoordinates initialPosition)
|
||||
{
|
||||
EntityUid = entityUid;
|
||||
PickupDirection = pickupDirection;
|
||||
FinalPosition = finalPosition;
|
||||
InitialPosition = initialPosition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Content.Shared.Spawning
|
||||
in Box2? box = null,
|
||||
SharedBroadphaseSystem? collision = null)
|
||||
{
|
||||
var boxOrDefault = box.GetValueOrDefault(Box2.UnitCentered);
|
||||
var boxOrDefault = box.GetValueOrDefault(Box2.UnitCentered).Translated(coordinates.Position);
|
||||
collision ??= EntitySystem.Get<SharedBroadphaseSystem>();
|
||||
|
||||
foreach (var body in collision.GetCollidingEntities(coordinates.MapId, in boxOrDefault))
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
@@ -10,6 +14,7 @@ namespace Content.Shared.SubFloor
|
||||
/// (plating).
|
||||
/// </summary>
|
||||
/// <seealso cref="P:Content.Shared.Maps.ContentTileDefinition.IsSubFloor" />
|
||||
[NetworkedComponent]
|
||||
[RegisterComponent]
|
||||
public sealed class SubFloorHideComponent : Component
|
||||
{
|
||||
@@ -17,10 +22,35 @@ namespace Content.Shared.SubFloor
|
||||
public override string Name => "SubFloorHide";
|
||||
|
||||
/// <summary>
|
||||
/// This entity needs to be anchored to be hid in the subfloor.
|
||||
/// Whether the entity will be hid when not in subfloor.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("enabled")]
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This entity needs to be anchored to be hid when not in subfloor.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("requireAnchored")]
|
||||
public bool RequireAnchored { get; set; } = true;
|
||||
|
||||
public override ComponentState GetComponentState(ICommonSession player)
|
||||
{
|
||||
return new SubFloorHideComponentState(Enabled, RequireAnchored);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class SubFloorHideComponentState : ComponentState
|
||||
{
|
||||
public bool Enabled { get; }
|
||||
public bool RequireAnchored { get; }
|
||||
|
||||
public SubFloorHideComponentState(bool enabled, bool requireAnchored)
|
||||
{
|
||||
Enabled = enabled;
|
||||
RequireAnchored = requireAnchored;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using Content.Shared.Maps;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Shared.SubFloor
|
||||
@@ -42,6 +45,7 @@ namespace Content.Shared.SubFloor
|
||||
SubscribeLocalEvent<SubFloorHideComponent, ComponentStartup>(OnSubFloorStarted);
|
||||
SubscribeLocalEvent<SubFloorHideComponent, ComponentShutdown>(OnSubFloorTerminating);
|
||||
SubscribeLocalEvent<SubFloorHideComponent, AnchorStateChangedEvent>(HandleAnchorChanged);
|
||||
SubscribeLocalEvent<SubFloorHideComponent, ComponentHandleState>(HandleComponentState);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
@@ -52,6 +56,20 @@ namespace Content.Shared.SubFloor
|
||||
_mapManager.TileChanged -= MapManagerOnTileChanged;
|
||||
}
|
||||
|
||||
public void SetEnabled(SubFloorHideComponent subFloor, bool enabled)
|
||||
{
|
||||
subFloor.Enabled = enabled;
|
||||
subFloor.Dirty();
|
||||
UpdateEntity(subFloor.Owner.Uid);
|
||||
}
|
||||
|
||||
public void SetRequireAnchoring(SubFloorHideComponent subFloor, bool requireAnchored)
|
||||
{
|
||||
subFloor.RequireAnchored = requireAnchored;
|
||||
subFloor.Dirty();
|
||||
UpdateEntity(subFloor.Owner.Uid);
|
||||
}
|
||||
|
||||
private void OnSubFloorStarted(EntityUid uid, SubFloorHideComponent component, ComponentStartup _)
|
||||
{
|
||||
UpdateEntity(uid);
|
||||
@@ -71,6 +89,16 @@ namespace Content.Shared.SubFloor
|
||||
UpdateEntity(uid);
|
||||
}
|
||||
|
||||
private void HandleComponentState(EntityUid uid, SubFloorHideComponent component, ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not SubFloorHideComponentState state)
|
||||
return;
|
||||
|
||||
component.Enabled = state.Enabled;
|
||||
component.RequireAnchored = state.RequireAnchored;
|
||||
UpdateEntity(uid);
|
||||
}
|
||||
|
||||
private void MapManagerOnTileChanged(object? sender, TileChangedEventArgs e)
|
||||
{
|
||||
UpdateTile(_mapManager.GetGrid(e.NewTile.GridIndex), e.NewTile.GridIndices);
|
||||
@@ -134,22 +162,36 @@ namespace Content.Shared.SubFloor
|
||||
if (subFloorHideEvent.Handled)
|
||||
return;
|
||||
|
||||
// This might look weird, but basically we only need to query the SubFloorHide and Transform components
|
||||
// if we are gonna hide the entity and we require it to be anchored to be hidden. Because getting components
|
||||
// is "expensive", we have a slow path where we query them, and a fast path where we don't.
|
||||
if (!subFloor
|
||||
&& ComponentManager.TryGetComponent(uid, out SubFloorHideComponent? subFloorHideComponent) &&
|
||||
subFloorHideComponent.RequireAnchored
|
||||
&& ComponentManager.TryGetComponent(uid, out ITransformComponent? transformComponent))
|
||||
// We only need to query the subfloor component to check if it's enabled or not when we're not on subfloor.
|
||||
// Getting components is expensive, after all.
|
||||
if (!subFloor && ComponentManager.TryGetComponent(uid, out SubFloorHideComponent? subFloorHideComponent))
|
||||
{
|
||||
// If we require the entity to be anchored but it's not, this will set subfloor to true, unhiding it.
|
||||
subFloor = !transformComponent.Anchored;
|
||||
// If the component isn't enabled, then subfloor will always be true, and the entity will be shown.
|
||||
if (!subFloorHideComponent.Enabled)
|
||||
{
|
||||
subFloor = true;
|
||||
}
|
||||
// We only need to query the TransformComp if the SubfloorHide is enabled and requires anchoring.
|
||||
else if (subFloorHideComponent.RequireAnchored && ComponentManager.TryGetComponent(uid, out ITransformComponent? transformComponent))
|
||||
{
|
||||
// If we require the entity to be anchored but it's not, this will set subfloor to true, unhiding it.
|
||||
subFloor = !transformComponent.Anchored;
|
||||
}
|
||||
}
|
||||
|
||||
// Whether to show this entity as visible, visually.
|
||||
var subFloorVisible = ShowAll || subFloor;
|
||||
|
||||
// Show sprite
|
||||
if (ComponentManager.TryGetComponent(uid, out SharedSpriteComponent? spriteComponent))
|
||||
{
|
||||
spriteComponent.Visible = ShowAll || subFloor;
|
||||
spriteComponent.Visible = subFloorVisible;
|
||||
}
|
||||
|
||||
// Set an appearance data value so visualizers can use this as needed.
|
||||
if (ComponentManager.TryGetComponent(uid, out SharedAppearanceComponent? appearanceComponent))
|
||||
{
|
||||
appearanceComponent.SetData(SubFloorVisuals.SubFloor, subFloorVisible);
|
||||
}
|
||||
|
||||
// So for collision all we care about is that the component is running.
|
||||
@@ -169,4 +211,10 @@ namespace Content.Shared.SubFloor
|
||||
SubFloor = subFloor;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum SubFloorVisuals : byte
|
||||
{
|
||||
SubFloor,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user