Merge branch 'master' into 2021-12-03-remove-IEntity-komm-süsser-todd
# Conflicts: # Content.Client/Crayon/CrayonDecalVisualizer.cs # Content.Client/Tabletop/TabletopSystem.cs # Content.IntegrationTests/Tests/InventoryHelpersTest.cs # Content.Server/AI/EntitySystems/AiSystem.cs # Content.Server/AI/Utility/AiLogic/UtilityAI.cs # Content.Server/AME/AMENodeGroup.cs # Content.Server/Administration/AdminVerbSystem.cs # Content.Server/Body/Systems/RespiratorSystem.cs # Content.Server/Chemistry/Components/InjectorComponent.cs # Content.Server/Chemistry/TileReactions/CleanTileReaction.cs # Content.Server/Chemistry/TileReactions/SpillTileReaction.cs # Content.Server/Crayon/CrayonComponent.cs # Content.Server/Doors/Components/ServerDoorComponent.cs # Content.Server/Explosion/EntitySystems/TriggerSystem.cs # Content.Server/Fluids/Components/MopComponent.cs # Content.Server/Fluids/Components/SpillExtensions.cs # Content.Server/Fluids/EntitySystems/PuddleSystem.cs # Content.Server/Instruments/InstrumentSystem.cs # Content.Server/Nutrition/EntitySystems/DrinkSystem.cs # Content.Server/Nutrition/EntitySystems/FoodSystem.cs # Content.Server/PneumaticCannon/PneumaticCannonSystem.cs # Content.Server/Storage/Components/EntityStorageComponent.cs # Content.Server/Storage/Components/StorageFillComponent.cs # Content.Server/Stunnable/StunbatonSystem.cs # Content.Server/Throwing/ThrowHelper.cs # Content.Server/Weapon/Ranged/Barrels/BarrelSystem.cs # Content.Server/Weapon/Ranged/Barrels/Components/ServerBatteryBarrelComponent.cs # Content.Server/Weapon/Ranged/ServerRangedWeaponComponent.cs # Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs # Content.Shared/Damage/Components/DamageableComponent.cs # Content.Shared/Damage/Systems/DamageableSystem.cs # Content.Shared/MobState/Components/MobStateComponent.cs # Content.Shared/Slippery/SharedSlipperySystem.cs
This commit is contained in:
@@ -300,12 +300,13 @@ namespace Content.Shared.CCVar
|
||||
CVarDef.Create("hud.fps_counter_visible", false, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
/*
|
||||
* AI
|
||||
* NPCs
|
||||
*/
|
||||
|
||||
public static readonly CVarDef<int> AIMaxUpdates =
|
||||
CVarDef.Create("ai.maxupdates", 64);
|
||||
public static readonly CVarDef<int> NPCMaxUpdates =
|
||||
CVarDef.Create("npc.max_updates", 64);
|
||||
|
||||
public static readonly CVarDef<bool> NPCEnabled = CVarDef.Create("npc.enabled", true);
|
||||
|
||||
/*
|
||||
* Net
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Shared.Sound;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -81,6 +82,12 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
public SoundSpecifier? EjectSound;
|
||||
// maybe default to /Audio/Machines/id_swipe.ogg?
|
||||
|
||||
/// <summary>
|
||||
/// Options used for playing the insert/eject sounds.
|
||||
/// </summary>
|
||||
[DataField("soundOptions")]
|
||||
public AudioParams SoundOptions = AudioParams.Default;
|
||||
|
||||
/// <summary>
|
||||
/// The name of this item slot. This will be shown to the user in the verb menu.
|
||||
/// </summary>
|
||||
@@ -116,6 +123,18 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
[DataField("ejectOnInteract")]
|
||||
public bool EjectOnInteract = false;
|
||||
|
||||
/// <summary>
|
||||
/// If true, and if this slot is attached to an item, then it will attempt to eject slot when to the slot is
|
||||
/// used in the user's hands.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Desirable for things like ranged weapons ('Z' to eject), but not desirable for others (e.g., PDA uses
|
||||
/// 'Z' to open UI). Unlike <see cref="EjectOnInteract"/>, this will not make any changes to the context
|
||||
/// menu, nor will it disable alt-click interactions.
|
||||
/// </remarks>
|
||||
[DataField("ejectOnUse")]
|
||||
public bool EjectOnUse = false;
|
||||
|
||||
/// <summary>
|
||||
/// Override the insert verb text. Defaults to [insert category] -> [item-name]. If not null, the verb will
|
||||
/// not be given a category.
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
|
||||
SubscribeLocalEvent<ItemSlotsComponent, InteractUsingEvent>(OnInteractUsing);
|
||||
SubscribeLocalEvent<ItemSlotsComponent, InteractHandEvent>(OnInteractHand);
|
||||
SubscribeLocalEvent<ItemSlotsComponent, UseInHandEvent>(OnUseInHand);
|
||||
|
||||
SubscribeLocalEvent<ItemSlotsComponent, GetAlternativeVerbsEvent>(AddEjectVerbs);
|
||||
SubscribeLocalEvent<ItemSlotsComponent, GetInteractionVerbsEvent>(AddInteractionVerbsVerbs);
|
||||
@@ -125,6 +126,25 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to eject an item from the first valid item slot.
|
||||
/// </summary>
|
||||
private void OnUseInHand(EntityUid uid, ItemSlotsComponent itemSlots, UseInHandEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
foreach (var slot in itemSlots.Slots.Values)
|
||||
{
|
||||
if (slot.Locked || !slot.EjectOnUse || slot.Item == null)
|
||||
continue;
|
||||
|
||||
args.Handled = true;
|
||||
TryEjectToHands(uid, slot, args.User);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to insert a held item in any fitting item slot. If a valid slot already contains an item, it will
|
||||
/// swap it out and place the old one in the user's hand.
|
||||
@@ -172,7 +192,7 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
// ContainerSlot automatically raises a directed EntInsertedIntoContainerMessage
|
||||
|
||||
if (slot.InsertSound != null)
|
||||
SoundSystem.Play(Filter.Pvs(uid), slot.InsertSound.GetSound(), uid);
|
||||
SoundSystem.Play(Filter.Pvs(uid), slot.InsertSound.GetSound(), uid, slot.SoundOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -267,7 +287,7 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
// ContainerSlot automatically raises a directed EntRemovedFromContainerMessage
|
||||
|
||||
if (slot.EjectSound != null)
|
||||
SoundSystem.Play(Filter.Pvs(uid), slot.EjectSound.GetSound(), uid);
|
||||
SoundSystem.Play(Filter.Pvs(uid), slot.EjectSound.GetSound(), uid, slot.SoundOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -317,7 +337,7 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
return false;
|
||||
|
||||
if (user != null && EntityManager.TryGetComponent(user.Value, out SharedHandsComponent? hands))
|
||||
hands.TryPutInAnyHand(item.Value);
|
||||
hands.TryPutInActiveHandOrAny(item.Value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -72,16 +72,4 @@ namespace Content.Shared.Crayon
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable, Prototype("crayonDecal")]
|
||||
public class CrayonDecalPrototype : IPrototype
|
||||
{
|
||||
[ViewVariables]
|
||||
[DataField("id", required: true)]
|
||||
public string ID { get; } = default!;
|
||||
|
||||
[DataField("spritePath")] public string SpritePath { get; } = string.Empty;
|
||||
|
||||
[DataField("decals")] public List<string> Decals { get; } = new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Acts;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Radiation;
|
||||
using Robust.Shared.Analyzers;
|
||||
@@ -13,8 +12,6 @@ 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;
|
||||
using Content.Shared.Database;
|
||||
|
||||
namespace Content.Shared.Damage
|
||||
{
|
||||
@@ -95,11 +92,7 @@ namespace Content.Shared.Damage
|
||||
damage.DamageDict.Add(typeID, damageValue);
|
||||
}
|
||||
|
||||
var actual = EntitySystem.Get<DamageableSystem>().TryChangeDamage(Owner, damage);
|
||||
|
||||
// should logging be disabled during rad storms? a lot of entities are going to be damaged.
|
||||
if (actual != null && !actual.Empty)
|
||||
EntitySystem.Get<SharedAdminLogSystem>().Add(LogType.Radiation, $"{Owner} took {actual.Total} radiation damage");
|
||||
EntitySystem.Get<DamageableSystem>().TryChangeDamage(Owner, damage);
|
||||
}
|
||||
|
||||
// TODO EXPLOSION Remove this.
|
||||
@@ -120,11 +113,7 @@ namespace Content.Shared.Damage
|
||||
damage.DamageDict.Add(typeID, damageValue);
|
||||
}
|
||||
|
||||
var actual = EntitySystem.Get<DamageableSystem>().TryChangeDamage(Owner, damage);
|
||||
|
||||
// will logging handle nukes?
|
||||
if (actual != null && !actual.Empty)
|
||||
EntitySystem.Get<SharedAdminLogSystem>().Add(LogType.Explosion, $"{Owner} took {actual.Total} explosion damage");
|
||||
EntitySystem.Get<DamageableSystem>().TryChangeDamage(Owner, damage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
@@ -15,8 +13,6 @@ namespace Content.Shared.Damage
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
[Dependency] private readonly SharedAdminLogSystem _logs = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<DamageableComponent, ComponentInit>(DamageableInit);
|
||||
@@ -24,45 +20,6 @@ namespace Content.Shared.Damage
|
||||
SubscribeLocalEvent<DamageableComponent, ComponentGetState>(DamageableGetState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the total damage value and optionally add to admin logs
|
||||
/// </summary>
|
||||
protected virtual void SetTotalDamage(DamageableComponent damageable, FixedPoint2 @new, bool logChange)
|
||||
{
|
||||
var owner = damageable.Owner;
|
||||
var old = damageable.TotalDamage;
|
||||
|
||||
if (@new == old)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
damageable.TotalDamage = @new;
|
||||
|
||||
if (!logChange)
|
||||
return;
|
||||
|
||||
LogType logType;
|
||||
string type;
|
||||
FixedPoint2 change;
|
||||
|
||||
if (@new > old)
|
||||
{
|
||||
logType = LogType.Damaged;
|
||||
type = "received";
|
||||
change = @new - old;
|
||||
}
|
||||
else
|
||||
{
|
||||
logType = LogType.Healed;
|
||||
type = "healed";
|
||||
change = old - @new;
|
||||
}
|
||||
|
||||
_logs.Add(logType, $"{owner} {type} {change} damage. Old: {old} | New: {@new}");
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a damageable component
|
||||
/// </summary>
|
||||
@@ -111,7 +68,7 @@ namespace Content.Shared.Damage
|
||||
public void SetDamage(DamageableComponent damageable, DamageSpecifier damage)
|
||||
{
|
||||
damageable.Damage = damage;
|
||||
DamageChanged(damageable, false);
|
||||
DamageChanged(damageable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -121,11 +78,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.
|
||||
/// </remarks>
|
||||
public void DamageChanged(DamageableComponent component, bool logChange, DamageSpecifier? damageDelta = null,
|
||||
public void DamageChanged(DamageableComponent component, DamageSpecifier? damageDelta = null,
|
||||
bool interruptsDoAfters = true)
|
||||
{
|
||||
component.DamagePerGroup = component.Damage.GetDamagePerGroup();
|
||||
SetTotalDamage(component, component.Damage.Total, logChange);
|
||||
component.TotalDamage = component.Damage.Total;
|
||||
component.Dirty();
|
||||
|
||||
if (EntityManager.TryGetComponent<AppearanceComponent>(component.Owner, out var appearance) && damageDelta != null)
|
||||
@@ -146,7 +103,7 @@ namespace Content.Shared.Damage
|
||||
/// null if the user had no applicable components that can take damage.
|
||||
/// </returns>
|
||||
public DamageSpecifier? TryChangeDamage(EntityUid? uid, DamageSpecifier damage, bool ignoreResistances = false,
|
||||
bool interruptsDoAfters = true, bool logChange = false)
|
||||
bool interruptsDoAfters = true)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent<DamageableComponent>(uid, out var damageable))
|
||||
{
|
||||
@@ -195,7 +152,7 @@ namespace Content.Shared.Damage
|
||||
|
||||
if (!delta.Empty)
|
||||
{
|
||||
DamageChanged(damageable, logChange, delta, interruptsDoAfters);
|
||||
DamageChanged(damageable, delta, interruptsDoAfters);
|
||||
}
|
||||
|
||||
return delta;
|
||||
@@ -222,7 +179,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, false, new DamageSpecifier());
|
||||
DamageChanged(component, new DamageSpecifier());
|
||||
}
|
||||
|
||||
private void DamageableGetState(EntityUid uid, DamageableComponent component, ref ComponentGetState args)
|
||||
@@ -247,7 +204,7 @@ namespace Content.Shared.Damage
|
||||
if (!delta.Empty)
|
||||
{
|
||||
component.Damage = newDamage;
|
||||
DamageChanged(component, false, delta);
|
||||
DamageChanged(component, delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
Content.Shared/Decals/Decal.cs
Normal file
38
Content.Shared/Decals/Decal.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Decals
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
[DataDefinition]
|
||||
public class Decal
|
||||
{
|
||||
[DataField("coordinates")] public readonly Vector2 Coordinates = Vector2.Zero;
|
||||
[DataField("id")] public readonly string Id = string.Empty;
|
||||
[DataField("color")] public readonly Color? Color;
|
||||
[DataField("angle")] public readonly Angle Angle = Angle.Zero;
|
||||
[DataField("zIndex")] public readonly int ZIndex;
|
||||
[DataField("cleanable")] public bool Cleanable;
|
||||
|
||||
public Decal() {}
|
||||
|
||||
public Decal(Vector2 coordinates, string id, Color? color, Angle angle, int zIndex, bool cleanable)
|
||||
{
|
||||
Coordinates = coordinates;
|
||||
Id = id;
|
||||
Color = color;
|
||||
Angle = angle;
|
||||
ZIndex = zIndex;
|
||||
Cleanable = cleanable;
|
||||
}
|
||||
|
||||
public Decal WithCoordinates(Vector2 coordinates) => new(coordinates, Id, Color, Angle, ZIndex, Cleanable);
|
||||
public Decal WithId(string id) => new(Coordinates, id, Color, Angle, ZIndex, Cleanable);
|
||||
public Decal WithColor(Color? color) => new(Coordinates, Id, color, Angle, ZIndex, Cleanable);
|
||||
public Decal WithRotation(Angle angle) => new(Coordinates, Id, Color, angle, ZIndex, Cleanable);
|
||||
public Decal WithZIndex(int zIndex) => new(Coordinates, Id, Color, Angle, zIndex, Cleanable);
|
||||
public Decal WithCleanable(bool cleanable) => new(Coordinates, Id, Color, Angle, ZIndex, cleanable);
|
||||
}
|
||||
}
|
||||
15
Content.Shared/Decals/DecalChunkUpdateEvent.cs
Normal file
15
Content.Shared/Decals/DecalChunkUpdateEvent.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Decals
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public class DecalChunkUpdateEvent : EntityEventArgs
|
||||
{
|
||||
public Dictionary<GridId, Dictionary<Vector2i, Dictionary<uint, Decal>>> Data = new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Serialization.Manager.Result;
|
||||
using Robust.Shared.Serialization.Markdown;
|
||||
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||
using Robust.Shared.Serialization.Markdown.Validation;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
|
||||
|
||||
namespace Content.Shared.Decals
|
||||
{
|
||||
[TypeSerializer]
|
||||
public class DecalGridChunkCollectionTypeSerializer : ITypeSerializer<DecalGridComponent.DecalGridChunkCollection, MappingDataNode>
|
||||
{
|
||||
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,
|
||||
IDependencyCollection dependencies, ISerializationContext? context = null)
|
||||
{
|
||||
return serializationManager.ValidateNode<Dictionary<Vector2i, Dictionary<uint, Decal>>>(node, context);
|
||||
}
|
||||
|
||||
public DeserializationResult Read(ISerializationManager serializationManager, MappingDataNode node,
|
||||
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
|
||||
{
|
||||
//todo this read method does not support pushing inheritance
|
||||
var dictionary =
|
||||
serializationManager.ReadValueOrThrow<Dictionary<Vector2i, Dictionary<uint, Decal>>>(node, context, skipHook);
|
||||
|
||||
var uids = new SortedSet<uint>();
|
||||
var uidChunkMap = new Dictionary<uint, Vector2i>();
|
||||
foreach (var (indices, decals) in dictionary)
|
||||
{
|
||||
foreach (var (uid, _) in decals)
|
||||
{
|
||||
uids.Add(uid);
|
||||
uidChunkMap[uid] = indices;
|
||||
}
|
||||
}
|
||||
|
||||
var uidMap = new Dictionary<uint, uint>();
|
||||
uint nextIndex = 0;
|
||||
foreach (var uid in uids)
|
||||
{
|
||||
uidMap[uid] = nextIndex++;
|
||||
}
|
||||
|
||||
var newDict = new Dictionary<Vector2i, Dictionary<uint, Decal>>();
|
||||
foreach (var (oldUid, newUid) in uidMap)
|
||||
{
|
||||
var indices = uidChunkMap[oldUid];
|
||||
if(!newDict.ContainsKey(indices))
|
||||
newDict[indices] = new();
|
||||
newDict[indices][newUid] = dictionary[indices][oldUid];
|
||||
}
|
||||
|
||||
return new DeserializedValue<DecalGridComponent.DecalGridChunkCollection>(
|
||||
new DecalGridComponent.DecalGridChunkCollection(newDict){NextUid = nextIndex});
|
||||
}
|
||||
|
||||
public DataNode Write(ISerializationManager serializationManager, DecalGridComponent.DecalGridChunkCollection value, bool alwaysWrite = false,
|
||||
ISerializationContext? context = null)
|
||||
{
|
||||
return serializationManager.WriteValue(value.ChunkCollection, alwaysWrite, context);
|
||||
}
|
||||
|
||||
public DecalGridComponent.DecalGridChunkCollection Copy(ISerializationManager serializationManager, DecalGridComponent.DecalGridChunkCollection source,
|
||||
DecalGridComponent.DecalGridChunkCollection target, bool skipHook, ISerializationContext? context = null)
|
||||
{
|
||||
var dict = serializationManager.Copy(source.ChunkCollection, target.ChunkCollection, context, skipHook)!;
|
||||
return new DecalGridComponent.DecalGridChunkCollection(dict) {NextUid = source.NextUid};
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Content.Shared/Decals/DecalGridComponent.cs
Normal file
23
Content.Shared/Decals/DecalGridComponent.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Decals
|
||||
{
|
||||
[RegisterComponent]
|
||||
[Friend(typeof(SharedDecalSystem))]
|
||||
public class DecalGridComponent : Component
|
||||
{
|
||||
public override string Name => "DecalGrid";
|
||||
|
||||
[DataField("chunkCollection", serverOnly: true)]
|
||||
public DecalGridChunkCollection ChunkCollection = new(new ());
|
||||
|
||||
public record DecalGridChunkCollection(Dictionary<Vector2i, Dictionary<uint, Decal>> ChunkCollection)
|
||||
{
|
||||
public uint NextUid;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Content.Shared/Decals/DecalPrototype.cs
Normal file
15
Content.Shared/Decals/DecalPrototype.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Decals
|
||||
{
|
||||
[Prototype("decal")]
|
||||
public class DecalPrototype : IPrototype
|
||||
{
|
||||
[DataField("id")] public string ID { get; } = null!;
|
||||
[DataField("sprite")] public SpriteSpecifier Sprite { get; } = SpriteSpecifier.Invalid;
|
||||
[DataField("tags")] public List<string> Tags = new();
|
||||
}
|
||||
}
|
||||
153
Content.Shared/Decals/SharedDecalSystem.cs
Normal file
153
Content.Shared/Decals/SharedDecalSystem.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Decals
|
||||
{
|
||||
public abstract class SharedDecalSystem : EntitySystem
|
||||
{
|
||||
[Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
[Dependency] protected readonly IMapManager MapManager = default!;
|
||||
|
||||
protected readonly Dictionary<GridId, Dictionary<uint, Vector2i>> ChunkIndex = new();
|
||||
|
||||
public const int ChunkSize = 32;
|
||||
public static Vector2i GetChunkIndices(Vector2 coordinates) => new ((int) Math.Floor(coordinates.X / ChunkSize), (int) Math.Floor(coordinates.Y / ChunkSize));
|
||||
|
||||
private float _viewSize;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GridInitializeEvent>(OnGridInitialize);
|
||||
_configurationManager.OnValueChanged(CVars.NetMaxUpdateRange, OnPvsRangeChanged, true);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
_configurationManager.UnsubValueChanged(CVars.NetMaxUpdateRange, OnPvsRangeChanged);
|
||||
}
|
||||
|
||||
private void OnPvsRangeChanged(float obj)
|
||||
{
|
||||
_viewSize = obj * 2f;
|
||||
}
|
||||
|
||||
private void OnGridInitialize(GridInitializeEvent msg)
|
||||
{
|
||||
var comp = EntityManager.EnsureComponent<DecalGridComponent>(MapManager.GetGrid(msg.GridId).GridEntityId);
|
||||
ChunkIndex[msg.GridId] = new();
|
||||
foreach (var (indices, decals) in comp.ChunkCollection.ChunkCollection)
|
||||
{
|
||||
foreach (var uid in decals.Keys)
|
||||
{
|
||||
ChunkIndex[msg.GridId][uid] = indices;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected DecalGridComponent.DecalGridChunkCollection DecalGridChunkCollection(GridId gridId) => EntityManager
|
||||
.GetComponent<DecalGridComponent>(MapManager.GetGrid(gridId).GridEntityId).ChunkCollection;
|
||||
protected Dictionary<Vector2i, Dictionary<uint, Decal>> ChunkCollection(GridId gridId) => DecalGridChunkCollection(gridId).ChunkCollection;
|
||||
|
||||
protected virtual void DirtyChunk(GridId id, Vector2i chunkIndices) {}
|
||||
|
||||
protected bool RemoveDecalInternal(GridId gridId, uint uid)
|
||||
{
|
||||
if (!RemoveDecalHook(gridId, uid)) return false;
|
||||
|
||||
if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var chunkCollection = ChunkCollection(gridId);
|
||||
if (!chunkCollection.TryGetValue(indices, out var chunk) || !chunk.Remove(uid))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chunkCollection[indices].Count == 0)
|
||||
chunkCollection.Remove(indices);
|
||||
|
||||
ChunkIndex[gridId]?.Remove(uid);
|
||||
DirtyChunk(gridId, indices);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool RemoveDecalHook(GridId gridId, uint uid) => true;
|
||||
|
||||
private (Box2 view, MapId mapId) CalcViewBounds(in EntityUid euid)
|
||||
{
|
||||
var xform = EntityManager.GetComponent<TransformComponent>(euid);
|
||||
|
||||
var view = Box2.UnitCentered.Scale(_viewSize).Translated(xform.WorldPosition);
|
||||
var map = xform.MapID;
|
||||
|
||||
return (view, map);
|
||||
}
|
||||
|
||||
protected Dictionary<GridId, HashSet<Vector2i>> GetChunksForViewers(HashSet<EntityUid> viewers)
|
||||
{
|
||||
var chunks = new Dictionary<GridId, HashSet<Vector2i>>();
|
||||
foreach (var viewerUid in viewers)
|
||||
{
|
||||
var (bounds, mapId) = CalcViewBounds(viewerUid);
|
||||
MapManager.FindGridsIntersectingEnumerator(mapId, bounds, out var gridsEnumerator, true);
|
||||
while(gridsEnumerator.MoveNext(out var grid))
|
||||
{
|
||||
if(!chunks.ContainsKey(grid.Index))
|
||||
chunks[grid.Index] = new();
|
||||
var enumerator = new ChunkIndicesEnumerator(grid.InvWorldMatrix.TransformBox(bounds), ChunkSize);
|
||||
while (enumerator.MoveNext(out var indices))
|
||||
{
|
||||
chunks[grid.Index].Add(indices.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
}
|
||||
|
||||
internal struct ChunkIndicesEnumerator
|
||||
{
|
||||
private Vector2i _chunkLB;
|
||||
private Vector2i _chunkRT;
|
||||
|
||||
private int _xIndex;
|
||||
private int _yIndex;
|
||||
|
||||
internal ChunkIndicesEnumerator(Box2 localAABB, int chunkSize)
|
||||
{
|
||||
_chunkLB = new Vector2i((int)Math.Floor(localAABB.Left / chunkSize), (int)Math.Floor(localAABB.Bottom / chunkSize));
|
||||
_chunkRT = new Vector2i((int)Math.Floor(localAABB.Right / chunkSize), (int)Math.Floor(localAABB.Top / chunkSize));
|
||||
|
||||
_xIndex = _chunkLB.X;
|
||||
_yIndex = _chunkLB.Y;
|
||||
}
|
||||
|
||||
public bool MoveNext([NotNullWhen(true)] out Vector2i? indices)
|
||||
{
|
||||
if (_yIndex > _chunkRT.Y)
|
||||
{
|
||||
_yIndex = _chunkLB.Y;
|
||||
_xIndex += 1;
|
||||
}
|
||||
|
||||
indices = new Vector2i(_xIndex, _yIndex);
|
||||
_yIndex += 1;
|
||||
|
||||
return _xIndex <= _chunkRT.X;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,12 +53,13 @@ namespace Content.Shared.Jittering
|
||||
/// </remarks>
|
||||
/// <param name="uid">Entity in question.</param>
|
||||
/// <param name="time">For how much time to apply the effect.</param>
|
||||
/// <param name="refresh">The status effect cooldown should be refreshed (true) or accumulated (false).</param>
|
||||
/// <param name="amplitude">Jitteriness of the animation. See <see cref="MaxAmplitude"/> and <see cref="MinAmplitude"/>.</param>
|
||||
/// <param name="frequency">Frequency for jittering. See <see cref="MaxFrequency"/> and <see cref="MinFrequency"/>.</param>
|
||||
/// <param name="forceValueChange">Whether to change any existing jitter value even if they're greater than the ones we're setting.</param>
|
||||
/// <param name="status">The status effects component to modify.</param>
|
||||
/// <param name="alerts">The alerts component.</param>
|
||||
public void DoJitter(EntityUid uid, TimeSpan time, float amplitude = 10f, float frequency = 4f, bool forceValueChange = false,
|
||||
public void DoJitter(EntityUid uid, TimeSpan time, bool refresh, float amplitude = 10f, float frequency = 4f, bool forceValueChange = false,
|
||||
StatusEffectsComponent? status = null,
|
||||
SharedAlertsComponent? alerts = null)
|
||||
{
|
||||
@@ -68,7 +69,7 @@ namespace Content.Shared.Jittering
|
||||
amplitude = Math.Clamp(amplitude, MinAmplitude, MaxAmplitude);
|
||||
frequency = Math.Clamp(frequency, MinFrequency, MaxFrequency);
|
||||
|
||||
if (StatusEffects.TryAddStatusEffect<JitteringComponent>(uid, "Jitter", time, status, alerts))
|
||||
if (StatusEffects.TryAddStatusEffect<JitteringComponent>(uid, "Jitter", time, refresh, status, alerts))
|
||||
{
|
||||
var jittering = EntityManager.GetComponent<JitteringComponent>(uid);
|
||||
|
||||
|
||||
@@ -289,9 +289,11 @@ namespace Content.Shared.MobState.Components
|
||||
/// </summary>
|
||||
private void SetMobState(IMobState? old, (IMobState state, FixedPoint2 threshold)? current)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
if (!current.HasValue)
|
||||
{
|
||||
old?.ExitState(Owner, IoCManager.Resolve<IEntityManager>());
|
||||
old?.ExitState(Owner, entMan);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -301,22 +303,19 @@ namespace Content.Shared.MobState.Components
|
||||
|
||||
if (state == old)
|
||||
{
|
||||
state.UpdateState(Owner, threshold, IoCManager.Resolve<IEntityManager>());
|
||||
state.UpdateState(Owner, threshold, entMan);
|
||||
return;
|
||||
}
|
||||
|
||||
old?.ExitState(Owner, IoCManager.Resolve<IEntityManager>());
|
||||
old?.ExitState(Owner, entMan);
|
||||
|
||||
CurrentState = state;
|
||||
|
||||
state.EnterState(Owner, IoCManager.Resolve<IEntityManager>());
|
||||
state.UpdateState(Owner, threshold, IoCManager.Resolve<IEntityManager>());
|
||||
state.EnterState(Owner, entMan);
|
||||
state.UpdateState(Owner, threshold, entMan);
|
||||
|
||||
var message = new MobStateChangedMessage(this, old, state);
|
||||
#pragma warning disable 618
|
||||
SendMessage(message);
|
||||
#pragma warning restore 618
|
||||
IoCManager.Resolve<IEntityManager>().EventBus.RaiseEvent(EventSource.Local, message);
|
||||
var message = new MobStateChangedEvent(this, old, state);
|
||||
entMan.EventBus.RaiseLocalEvent(Owner, message);
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
@@ -4,11 +4,9 @@ using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.MobState
|
||||
{
|
||||
#pragma warning disable 618
|
||||
public class MobStateChangedMessage : ComponentMessage
|
||||
#pragma warning restore 618
|
||||
public class MobStateChangedEvent : EntityEventArgs
|
||||
{
|
||||
public MobStateChangedMessage(
|
||||
public MobStateChangedEvent(
|
||||
MobStateComponent component,
|
||||
IMobState? oldMobState,
|
||||
IMobState currentMobState)
|
||||
@@ -68,7 +68,7 @@ namespace Content.Shared.Nutrition.EntitySystems
|
||||
|
||||
CreamedEntity(uid, creamPied, args);
|
||||
|
||||
_stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(creamPie.ParalyzeTime));
|
||||
_stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(creamPie.ParalyzeTime), true);
|
||||
}
|
||||
|
||||
protected virtual void CreamedEntity(EntityUid uid, CreamPiedComponent creamPied, ThrowHitByEvent args) {}
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Content.Shared.Slippery
|
||||
if (!component.Slippery
|
||||
|| component.Owner.IsInContainer()
|
||||
|| component.Slipped.Contains(uid)
|
||||
|| !_statusEffectsSystem.CanApplyEffect(uid, "Stun"))
|
||||
|| !_statusEffectsSystem.CanApplyEffect(uid, "Stun")) //Should be KnockedDown instead?
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -94,11 +94,17 @@ namespace Content.Shared.Slippery
|
||||
|
||||
otherBody.LinearVelocity *= component.LaunchForwardsMultiplier;
|
||||
|
||||
_stunSystem.TryParalyze(otherBody.Owner, TimeSpan.FromSeconds(5));
|
||||
bool playSound = !_statusEffectsSystem.HasStatusEffect(otherBody.Owner, "KnockedDown");
|
||||
|
||||
_stunSystem.TryParalyze(otherBody.Owner, TimeSpan.FromSeconds(component.ParalyzeTime), true);
|
||||
component.Slipped.Add(otherBody.Owner);
|
||||
component.Dirty();
|
||||
|
||||
PlaySound(component);
|
||||
//Preventing from playing the slip sound when you are already knocked down.
|
||||
if(playSound)
|
||||
{
|
||||
PlaySound(component);
|
||||
}
|
||||
|
||||
_adminLog.Add(LogType.Slip, LogImpact.Low, $"{component.Owner} slipped on collision with {otherBody.Owner}");
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Content.Shared.Slippery
|
||||
{
|
||||
public override string Name => "Slippery";
|
||||
|
||||
private float _paralyzeTime = 3f;
|
||||
private float _paralyzeTime = 5f;
|
||||
private float _intersectPercentage = 0.3f;
|
||||
private float _requiredSlipSpeed = 5f;
|
||||
private float _launchForwardsMultiplier = 1f;
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Content.Shared.Speech.EntitySystems
|
||||
public abstract class SharedStutteringSystem : EntitySystem
|
||||
{
|
||||
// For code in shared... I imagine we ain't getting accent prediction anytime soon so let's not bother.
|
||||
public virtual void DoStutter(EntityUid uid, TimeSpan time, StatusEffectsComponent? status = null, SharedAlertsComponent? alerts = null)
|
||||
public virtual void DoStutter(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent? status = null, SharedAlertsComponent? alerts = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,13 @@ namespace Content.Shared.StatusEffect
|
||||
[ViewVariables]
|
||||
public (TimeSpan, TimeSpan) Cooldown;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies whether to refresh or accumulate the cooldown of the status effect.
|
||||
/// true - refresh time, false - accumulate time.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool CooldownRefresh = true;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the relevant component that
|
||||
/// was added alongside the effect, if any.
|
||||
@@ -45,9 +52,10 @@ namespace Content.Shared.StatusEffect
|
||||
[ViewVariables]
|
||||
public string? RelevantComponent;
|
||||
|
||||
public StatusEffectState((TimeSpan, TimeSpan) cooldown, string? relevantComponent=null)
|
||||
public StatusEffectState((TimeSpan, TimeSpan) cooldown, bool refresh, string? relevantComponent=null)
|
||||
{
|
||||
Cooldown = cooldown;
|
||||
CooldownRefresh = refresh;
|
||||
RelevantComponent = relevantComponent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,8 @@ namespace Content.Shared.StatusEffect
|
||||
}
|
||||
|
||||
var time = effect.Value.Cooldown.Item2 - effect.Value.Cooldown.Item1;
|
||||
TryAddStatusEffect(uid, effect.Key, time);
|
||||
//TODO: Not sure how to handle refresh here.
|
||||
TryAddStatusEffect(uid, effect.Key, time, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,11 +76,12 @@ namespace Content.Shared.StatusEffect
|
||||
/// <param name="uid">The entity to add the effect to.</param>
|
||||
/// <param name="key">The status effect ID to add.</param>
|
||||
/// <param name="time">How long the effect should last for.</param>
|
||||
/// <param name="refresh">The status effect cooldown should be refreshed (true) or accumulated (false).</param>
|
||||
/// <param name="status">The status effects component to change, if you already have it.</param>
|
||||
/// <param name="alerts">The alerts component to modify, if the status effect has an alert.</param>
|
||||
/// <returns>False if the effect could not be added or the component already exists, true otherwise.</returns>
|
||||
/// <typeparam name="T">The component type to add and remove from the entity.</typeparam>
|
||||
public bool TryAddStatusEffect<T>(EntityUid uid, string key, TimeSpan time,
|
||||
public bool TryAddStatusEffect<T>(EntityUid uid, string key, TimeSpan time, bool refresh,
|
||||
StatusEffectsComponent? status=null,
|
||||
SharedAlertsComponent? alerts=null)
|
||||
where T: Component, new()
|
||||
@@ -89,7 +91,7 @@ namespace Content.Shared.StatusEffect
|
||||
|
||||
Resolve(uid, ref alerts, false);
|
||||
|
||||
if (TryAddStatusEffect(uid, key, time, status, alerts))
|
||||
if (TryAddStatusEffect(uid, key, time, refresh, status, alerts))
|
||||
{
|
||||
// If they already have the comp, we just won't bother updating anything.
|
||||
if (!EntityManager.HasComponent<T>(uid))
|
||||
@@ -103,7 +105,7 @@ namespace Content.Shared.StatusEffect
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, string component,
|
||||
public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, string component,
|
||||
StatusEffectsComponent? status = null,
|
||||
SharedAlertsComponent? alerts = null)
|
||||
{
|
||||
@@ -112,7 +114,7 @@ namespace Content.Shared.StatusEffect
|
||||
|
||||
Resolve(uid, ref alerts, false);
|
||||
|
||||
if (TryAddStatusEffect(uid, key, time, status, alerts))
|
||||
if (TryAddStatusEffect(uid, key, time, refresh, status, alerts))
|
||||
{
|
||||
// If they already have the comp, we just won't bother updating anything.
|
||||
if (!EntityManager.HasComponent(uid, _componentFactory.GetRegistration(component).Type))
|
||||
@@ -136,6 +138,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// <param name="uid">The entity to add the effect to.</param>
|
||||
/// <param name="key">The status effect ID to add.</param>
|
||||
/// <param name="time">How long the effect should last for.</param>
|
||||
/// <param name="refresh">The status effect cooldown should be refreshed (true) or accumulated (false).</param>
|
||||
/// <param name="status">The status effects component to change, if you already have it.</param>
|
||||
/// <param name="alerts">The alerts component to modify, if the status effect has an alert.</param>
|
||||
/// <returns>False if the effect could not be added, or if the effect already existed.</returns>
|
||||
@@ -146,7 +149,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// If the effect already exists, it will simply replace the cooldown with the new one given.
|
||||
/// If you want special 'effect merging' behavior, do it your own damn self!
|
||||
/// </remarks>
|
||||
public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time,
|
||||
public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh,
|
||||
StatusEffectsComponent? status=null,
|
||||
SharedAlertsComponent? alerts=null)
|
||||
{
|
||||
@@ -163,14 +166,27 @@ namespace Content.Shared.StatusEffect
|
||||
|
||||
(TimeSpan, TimeSpan) cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + time);
|
||||
|
||||
// If they already have this status effect, add the time onto it's cooldown rather than anything else.
|
||||
if (HasStatusEffect(uid, key, status))
|
||||
{
|
||||
status.ActiveEffects[key].Cooldown.Item2 += time;
|
||||
status.ActiveEffects[key].CooldownRefresh = refresh;
|
||||
if(refresh)
|
||||
{
|
||||
//Making sure we don't reset a longer cooldown by applying a shorter one.
|
||||
if((status.ActiveEffects[key].Cooldown.Item2 - _gameTiming.CurTime) < time)
|
||||
{
|
||||
//Refresh cooldown time.
|
||||
status.ActiveEffects[key].Cooldown = cooldown;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Accumulate cooldown time.
|
||||
status.ActiveEffects[key].Cooldown.Item2 += time;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status.ActiveEffects.Add(key, new StatusEffectState(cooldown, null));
|
||||
status.ActiveEffects.Add(key, new StatusEffectState(cooldown, refresh, null));
|
||||
}
|
||||
|
||||
if (proto.Alert != null && alerts != null)
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Content.Shared.Stunnable
|
||||
/// <summary>
|
||||
/// Stuns the entity, disallowing it from doing many interactions temporarily.
|
||||
/// </summary>
|
||||
public bool TryStun(EntityUid uid, TimeSpan time,
|
||||
public bool TryStun(EntityUid uid, TimeSpan time, bool refresh,
|
||||
StatusEffectsComponent? status = null,
|
||||
SharedAlertsComponent? alerts = null)
|
||||
{
|
||||
@@ -130,13 +130,13 @@ namespace Content.Shared.Stunnable
|
||||
|
||||
Resolve(uid, ref alerts, false);
|
||||
|
||||
return _statusEffectSystem.TryAddStatusEffect<StunnedComponent>(uid, "Stun", time, alerts: alerts);
|
||||
return _statusEffectSystem.TryAddStatusEffect<StunnedComponent>(uid, "Stun", time, refresh, alerts: alerts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Knocks down the entity, making it fall to the ground.
|
||||
/// </summary>
|
||||
public bool TryKnockdown(EntityUid uid, TimeSpan time,
|
||||
public bool TryKnockdown(EntityUid uid, TimeSpan time, bool refresh,
|
||||
StatusEffectsComponent? status = null,
|
||||
SharedAlertsComponent? alerts = null)
|
||||
{
|
||||
@@ -148,13 +148,13 @@ namespace Content.Shared.Stunnable
|
||||
|
||||
Resolve(uid, ref alerts, false);
|
||||
|
||||
return _statusEffectSystem.TryAddStatusEffect<KnockedDownComponent>(uid, "KnockedDown", time, alerts: alerts);
|
||||
return _statusEffectSystem.TryAddStatusEffect<KnockedDownComponent>(uid, "KnockedDown", time, refresh, alerts: alerts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies knockdown and stun to the entity temporarily.
|
||||
/// </summary>
|
||||
public bool TryParalyze(EntityUid uid, TimeSpan time,
|
||||
public bool TryParalyze(EntityUid uid, TimeSpan time, bool refresh,
|
||||
StatusEffectsComponent? status = null,
|
||||
SharedAlertsComponent? alerts = null)
|
||||
{
|
||||
@@ -164,13 +164,13 @@ namespace Content.Shared.Stunnable
|
||||
// Optional component.
|
||||
Resolve(uid, ref alerts, false);
|
||||
|
||||
return TryKnockdown(uid, time, status, alerts) && TryStun(uid, time, status, alerts);
|
||||
return TryKnockdown(uid, time, refresh, status, alerts) && TryStun(uid, time, refresh, status, alerts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Slows down the mob's walking/running speed temporarily
|
||||
/// </summary>
|
||||
public bool TrySlowdown(EntityUid uid, TimeSpan time,
|
||||
public bool TrySlowdown(EntityUid uid, TimeSpan time, bool refresh,
|
||||
float walkSpeedMultiplier = 1f, float runSpeedMultiplier = 1f,
|
||||
StatusEffectsComponent? status = null,
|
||||
SharedAlertsComponent? alerts = null)
|
||||
@@ -184,7 +184,7 @@ namespace Content.Shared.Stunnable
|
||||
if (time <= TimeSpan.Zero)
|
||||
return false;
|
||||
|
||||
if (_statusEffectSystem.TryAddStatusEffect<SlowedDownComponent>(uid, "SlowedDown", time, status, alerts))
|
||||
if (_statusEffectSystem.TryAddStatusEffect<SlowedDownComponent>(uid, "SlowedDown", time, refresh, status, alerts))
|
||||
{
|
||||
var slowed = EntityManager.GetComponent<SlowedDownComponent>(uid);
|
||||
// Doesn't make much sense to have the "TrySlowdown" method speed up entities now does it?
|
||||
|
||||
Reference in New Issue
Block a user