Merge branch 'master' into ion-storm-refactor
This commit is contained in:
@@ -33,6 +33,12 @@ public sealed partial class ToggleClothingComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool DisableOnUnequip;
|
||||
|
||||
/// <summary>
|
||||
/// If true, the clothes must equip for adding action.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool MustEquip = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -39,8 +39,12 @@ public sealed class ToggleClothingSystem : EntitySystem
|
||||
|
||||
private void OnGetActions(Entity<ToggleClothingComponent> ent, ref GetItemActionsEvent args)
|
||||
{
|
||||
if (args.InHands && ent.Comp.MustEquip)
|
||||
return;
|
||||
|
||||
var ev = new ToggleClothingCheckEvent(args.User);
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
|
||||
if (!ev.Cancelled)
|
||||
args.AddAction(ent.Comp.ActionEntity);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,23 @@ using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Crayon
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Component holding the state of a crayon-like component
|
||||
/// </summary>
|
||||
[NetworkedComponent, ComponentProtoName("Crayon"), Access(typeof(SharedCrayonSystem))]
|
||||
public abstract partial class SharedCrayonComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of currently selected decal prototype that will be placed when the crayon is used
|
||||
/// </summary>
|
||||
public string SelectedState { get; set; } = string.Empty;
|
||||
|
||||
[DataField("color")] public Color Color;
|
||||
/// <summary>
|
||||
/// Color with which the crayon will draw
|
||||
/// </summary>
|
||||
[DataField("color")]
|
||||
public Color Color;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum CrayonUiKey : byte
|
||||
@@ -17,6 +28,9 @@ namespace Content.Shared.Crayon
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by the client to notify the server about the selected decal ID
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CrayonSelectMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
@@ -27,6 +41,9 @@ namespace Content.Shared.Crayon
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the color of the crayon, used by Rainbow Crayon
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CrayonColorMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
@@ -37,13 +54,25 @@ namespace Content.Shared.Crayon
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server to CLIENT. Notifies the BUI that a decal with given ID has been drawn.
|
||||
/// Allows the client UI to advance forward in the client-only ephemeral queue,
|
||||
/// preventing the crayon from becoming a magic text storage device.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum CrayonVisuals
|
||||
public sealed class CrayonUsedMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
State,
|
||||
Color
|
||||
public readonly string DrawnDecal;
|
||||
|
||||
public CrayonUsedMessage(string drawn)
|
||||
{
|
||||
DrawnDecal = drawn;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Component state, describes how many charges are left in the crayon in the near-hand UI
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CrayonComponentState : ComponentState
|
||||
{
|
||||
@@ -60,10 +89,17 @@ namespace Content.Shared.Crayon
|
||||
Capacity = capacity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The state of the crayon UI as sent by the server
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CrayonBoundUserInterfaceState : BoundUserInterfaceState
|
||||
{
|
||||
public string Selected;
|
||||
/// <summary>
|
||||
/// Whether or not the color can be selected
|
||||
/// </summary>
|
||||
public bool SelectableColor;
|
||||
public Color Color;
|
||||
|
||||
|
||||
@@ -61,6 +61,12 @@ public sealed class DamageExamineSystem : EntitySystem
|
||||
}
|
||||
else
|
||||
{
|
||||
if (damageSpecifier.GetTotal() == FixedPoint2.Zero && !damageSpecifier.AnyPositive())
|
||||
{
|
||||
msg.AddMarkupOrThrow(Loc.GetString("damage-none"));
|
||||
return msg;
|
||||
}
|
||||
|
||||
msg.AddMarkupOrThrow(Loc.GetString("damage-examine-type", ("type", type)));
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,13 @@ public sealed class EmagSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows a popup to emag user (client side only!) and adds <see cref="EmaggedComponent"/> to the entity when handled
|
||||
/// </summary>
|
||||
/// <param name="UserUid">Emag user</param>
|
||||
/// <param name="Handled">Did the emagging succeed? Causes a user-only popup to show on client side</param>
|
||||
/// <param name="Repeatable">Can the entity be emagged more than once? Prevents adding of <see cref="EmaggedComponent"/></param>
|
||||
/// <remarks>Needs to be handled in shared/client, not just the server, to actually show the emagging popup</remarks>
|
||||
[ByRefEvent]
|
||||
public record struct GotEmaggedEvent(EntityUid UserUid, bool Handled = false, bool Repeatable = false);
|
||||
|
||||
|
||||
@@ -66,5 +66,5 @@ public record struct GenerateDnaEvent()
|
||||
/// <summary>
|
||||
/// The generated DNA.
|
||||
/// </summary>
|
||||
public string DNA;
|
||||
public required string DNA;
|
||||
}
|
||||
|
||||
33
Content.Shared/GameTicking/PlayerBeforeSpawnEvent.cs
Normal file
33
Content.Shared/GameTicking/PlayerBeforeSpawnEvent.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Content.Shared.Preferences;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Shared.GameTicking;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised broadcast before a player is spawned by the GameTicker.
|
||||
/// You can use this event to spawn a player off-station on late-join but also at round start.
|
||||
/// When this event is handled, the GameTicker will not perform its own player-spawning logic.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class PlayerBeforeSpawnEvent : HandledEntityEventArgs
|
||||
{
|
||||
public ICommonSession Player { get; }
|
||||
public HumanoidCharacterProfile Profile { get; }
|
||||
public string? JobId { get; }
|
||||
public bool LateJoin { get; }
|
||||
public EntityUid Station { get; }
|
||||
|
||||
public PlayerBeforeSpawnEvent(ICommonSession player,
|
||||
HumanoidCharacterProfile profile,
|
||||
string? jobId,
|
||||
bool lateJoin,
|
||||
EntityUid station)
|
||||
{
|
||||
Player = player;
|
||||
Profile = profile;
|
||||
JobId = jobId;
|
||||
LateJoin = lateJoin;
|
||||
Station = station;
|
||||
}
|
||||
}
|
||||
44
Content.Shared/GameTicking/PlayerSpawnCompleteEvent.cs
Normal file
44
Content.Shared/GameTicking/PlayerSpawnCompleteEvent.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using Content.Shared.Preferences;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Shared.GameTicking;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised both directed and broadcast when a player has been spawned by the GameTicker.
|
||||
/// You can use this to handle people late-joining, or to handle people being spawned at round start.
|
||||
/// Can be used to give random players a role, modify their equipment, etc.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class PlayerSpawnCompleteEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid Mob { get; }
|
||||
public ICommonSession Player { get; }
|
||||
public string? JobId { get; }
|
||||
public bool LateJoin { get; }
|
||||
public bool Silent { get; }
|
||||
public EntityUid Station { get; }
|
||||
public HumanoidCharacterProfile Profile { get; }
|
||||
|
||||
// Ex. If this is the 27th person to join, this will be 27.
|
||||
public int JoinOrder { get; }
|
||||
|
||||
public PlayerSpawnCompleteEvent(EntityUid mob,
|
||||
ICommonSession player,
|
||||
string? jobId,
|
||||
bool lateJoin,
|
||||
bool silent,
|
||||
int joinOrder,
|
||||
EntityUid station,
|
||||
HumanoidCharacterProfile profile)
|
||||
{
|
||||
Mob = mob;
|
||||
Player = player;
|
||||
JobId = jobId;
|
||||
LateJoin = lateJoin;
|
||||
Silent = silent;
|
||||
Station = station;
|
||||
Profile = profile;
|
||||
JoinOrder = joinOrder;
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,18 @@ public sealed partial class ItemToggleComponent : Component
|
||||
[DataField]
|
||||
public bool OnUse = true;
|
||||
|
||||
/// <summary>
|
||||
/// The localized text to display in the verb to activate.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string VerbToggleOn = "item-toggle-activate";
|
||||
|
||||
/// <summary>
|
||||
/// The localized text to display in the verb to de-activate.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string VerbToggleOff = "item-toggle-deactivate";
|
||||
|
||||
/// <summary>
|
||||
/// Whether the item's toggle can be predicted by the client.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
using Content.Shared.Item.ItemToggle;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Item.ItemToggle.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a verb for toggling something, requires <see cref="ItemToggleComponent"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(ToggleVerbSystem))]
|
||||
public sealed partial class ToggleVerbComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Text the verb will have.
|
||||
/// Gets passed "entity" as the entity's identity string.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public LocId Text = string.Empty;
|
||||
}
|
||||
@@ -78,7 +78,7 @@ public sealed class ItemToggleSystem : EntitySystem
|
||||
|
||||
args.Verbs.Add(new ActivationVerb()
|
||||
{
|
||||
Text = !ent.Comp.Activated ? Loc.GetString("item-toggle-activate") : Loc.GetString("item-toggle-deactivate"),
|
||||
Text = !ent.Comp.Activated ? Loc.GetString(ent.Comp.VerbToggleOn) : Loc.GetString(ent.Comp.VerbToggleOff),
|
||||
Act = () =>
|
||||
{
|
||||
Toggle((ent.Owner, ent.Comp), user, predicted: ent.Comp.Predictable);
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Item.ItemToggle.Components;
|
||||
using Content.Shared.Verbs;
|
||||
|
||||
namespace Content.Shared.Item.ItemToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a verb for toggling something with <see cref="ToggleVerbComponent"/>.
|
||||
/// </summary>
|
||||
public sealed class ToggleVerbSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ItemToggleSystem _toggle = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ToggleVerbComponent, GetVerbsEvent<ActivationVerb>>(OnGetVerbs);
|
||||
}
|
||||
|
||||
private void OnGetVerbs(Entity<ToggleVerbComponent> ent, ref GetVerbsEvent<ActivationVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
|
||||
var name = Identity.Entity(ent, EntityManager);
|
||||
var user = args.User;
|
||||
args.Verbs.Add(new ActivationVerb()
|
||||
{
|
||||
Text = Loc.GetString(ent.Comp.Text, ("entity", name)),
|
||||
Act = () => _toggle.Toggle(ent.Owner, user)
|
||||
});
|
||||
}
|
||||
}
|
||||
23
Content.Shared/Magic/Events/RandomGlobalSpawnSpellEvent.cs
Normal file
23
Content.Shared/Magic/Events/RandomGlobalSpawnSpellEvent.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Storage;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Shared.Magic.Events;
|
||||
|
||||
public sealed partial class RandomGlobalSpawnSpellEvent : InstantActionEvent, ISpeakSpell
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of prototypes this spell can spawn, will select one randomly
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<EntitySpawnEntry> Spawns = new();
|
||||
|
||||
/// <summary>
|
||||
/// Sound that will play globally when cast
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Magic/staff_animation.ogg");
|
||||
|
||||
[DataField]
|
||||
public string? Speech { get; private set; }
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Numerics;
|
||||
using System.Numerics;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Systems;
|
||||
@@ -7,12 +7,17 @@ using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Doors.Systems;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Lock;
|
||||
using Content.Shared.Magic.Components;
|
||||
using Content.Shared.Magic.Events;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Speech.Muting;
|
||||
@@ -20,6 +25,7 @@ using Content.Shared.Storage;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Network;
|
||||
@@ -53,6 +59,9 @@ public abstract class SharedMagicSystem : EntitySystem
|
||||
[Dependency] private readonly LockSystem _lock = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -67,6 +76,7 @@ public abstract class SharedMagicSystem : EntitySystem
|
||||
SubscribeLocalEvent<SmiteSpellEvent>(OnSmiteSpell);
|
||||
SubscribeLocalEvent<KnockSpellEvent>(OnKnockSpell);
|
||||
SubscribeLocalEvent<ChargeSpellEvent>(OnChargeSpell);
|
||||
SubscribeLocalEvent<RandomGlobalSpawnSpellEvent>(OnRandomGlobalSpawnSpell);
|
||||
|
||||
// Spell wishlist
|
||||
// A wishlish of spells that I'd like to implement or planning on implementing in a future PR
|
||||
@@ -501,6 +511,37 @@ public abstract class SharedMagicSystem : EntitySystem
|
||||
_gunSystem.UpdateBasicEntityAmmoCount(wand.Value, basicAmmoComp.Count.Value + ev.Charge, basicAmmoComp);
|
||||
}
|
||||
// End Charge Spells
|
||||
#endregion
|
||||
#region Global Spells
|
||||
|
||||
private void OnRandomGlobalSpawnSpell(RandomGlobalSpawnSpellEvent ev)
|
||||
{
|
||||
if (!_net.IsServer || ev.Handled || !PassesSpellPrerequisites(ev.Action, ev.Performer) || ev.Spawns is not { } spawns)
|
||||
return;
|
||||
|
||||
ev.Handled = true;
|
||||
Speak(ev);
|
||||
|
||||
var allHumans = _mind.GetAliveHumans();
|
||||
|
||||
foreach (var human in allHumans)
|
||||
{
|
||||
if (!human.Comp.OwnedEntity.HasValue)
|
||||
continue;
|
||||
|
||||
var ent = human.Comp.OwnedEntity.Value;
|
||||
|
||||
var mapCoords = _transform.GetMapCoordinates(ent);
|
||||
foreach (var spawn in EntitySpawnCollection.GetSpawns(spawns, _random))
|
||||
{
|
||||
var spawned = Spawn(spawn, mapCoords);
|
||||
_hands.PickupOrDrop(ent, spawned);
|
||||
}
|
||||
}
|
||||
|
||||
_audio.PlayGlobal(ev.Sound, ev.Performer);
|
||||
}
|
||||
|
||||
#endregion
|
||||
// End Spells
|
||||
#endregion
|
||||
|
||||
@@ -532,22 +532,19 @@ public abstract class SharedMindSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Returns a list of every living humanoid player's minds, except for a single one which is exluded.
|
||||
/// </summary>
|
||||
public List<EntityUid> GetAliveHumansExcept(EntityUid exclude)
|
||||
public HashSet<Entity<MindComponent>> GetAliveHumans(EntityUid? exclude = null)
|
||||
{
|
||||
var mindQuery = EntityQuery<MindComponent>();
|
||||
|
||||
var allHumans = new List<EntityUid>();
|
||||
var allHumans = new HashSet<Entity<MindComponent>>();
|
||||
// HumanoidAppearanceComponent is used to prevent mice, pAIs, etc from being chosen
|
||||
var query = EntityQueryEnumerator<MindContainerComponent, MobStateComponent, HumanoidAppearanceComponent>();
|
||||
while (query.MoveNext(out var uid, out var mc, out var mobState, out _))
|
||||
var query = EntityQueryEnumerator<MobStateComponent, HumanoidAppearanceComponent>();
|
||||
while (query.MoveNext(out var uid, out var mobState, out _))
|
||||
{
|
||||
// the player needs to have a mind and not be the excluded one
|
||||
if (mc.Mind == null || mc.Mind == exclude)
|
||||
// the player needs to have a mind and not be the excluded one +
|
||||
// the player has to be alive
|
||||
if (!TryGetMind(uid, out var mind, out var mindComp) || mind == exclude || !_mobState.IsAlive(uid, mobState))
|
||||
continue;
|
||||
|
||||
// the player has to be alive
|
||||
if (_mobState.IsAlive(uid, mobState))
|
||||
allHumans.Add(mc.Mind.Value);
|
||||
allHumans.Add(new Entity<MindComponent>(mind, mindComp));
|
||||
}
|
||||
|
||||
return allHumans;
|
||||
|
||||
@@ -26,10 +26,10 @@ public abstract partial class SharedSalvageSystem : EntitySystem
|
||||
[ValidatePrototypeId<SalvageLootPrototype>]
|
||||
public const string ExpeditionsLootProto = "SalvageLoot";
|
||||
|
||||
public static string GetFTLName(DatasetPrototype dataset, int seed)
|
||||
public string GetFTLName(LocalizedDatasetPrototype dataset, int seed)
|
||||
{
|
||||
var random = new System.Random(seed);
|
||||
return $"{dataset.Values[random.Next(dataset.Values.Count)]}-{random.Next(10, 100)}-{(char) (65 + random.Next(26))}";
|
||||
return $"{Loc.GetString(dataset.Values[random.Next(dataset.Values.Count)])}-{random.Next(10, 100)}-{(char) (65 + random.Next(26))}";
|
||||
}
|
||||
|
||||
public SalvageMission GetMission(SalvageDifficultyPrototype difficulty, int seed)
|
||||
|
||||
@@ -56,6 +56,7 @@ public sealed class StationAiVisionSystem : EntitySystem
|
||||
EntManager = EntityManager,
|
||||
Maps = _maps,
|
||||
System = this,
|
||||
VisibleTiles = _singleTiles,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -278,7 +279,7 @@ public sealed class StationAiVisionSystem : EntitySystem
|
||||
/// </summary>
|
||||
private record struct SeedJob() : IRobustJob
|
||||
{
|
||||
public StationAiVisionSystem System;
|
||||
public required StationAiVisionSystem System;
|
||||
|
||||
public Entity<MapGridComponent> Grid;
|
||||
public Box2 ExpandedBounds;
|
||||
@@ -293,14 +294,14 @@ public sealed class StationAiVisionSystem : EntitySystem
|
||||
{
|
||||
public int BatchSize => 1;
|
||||
|
||||
public IEntityManager EntManager;
|
||||
public SharedMapSystem Maps;
|
||||
public StationAiVisionSystem System;
|
||||
public required IEntityManager EntManager;
|
||||
public required SharedMapSystem Maps;
|
||||
public required StationAiVisionSystem System;
|
||||
|
||||
public Entity<MapGridComponent> Grid;
|
||||
public List<Entity<StationAiVisionComponent>> Data = new();
|
||||
|
||||
public HashSet<Vector2i> VisibleTiles;
|
||||
public required HashSet<Vector2i> VisibleTiles;
|
||||
|
||||
public readonly List<Dictionary<Vector2i, int>> Vis1 = new();
|
||||
public readonly List<Dictionary<Vector2i, int>> Vis2 = new();
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
using Content.Shared.Physics;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Singularity.Components;
|
||||
|
||||
[RegisterComponent, AutoGenerateComponentPause, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class SingularityGeneratorComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The amount of power this generator has accumulated.
|
||||
/// If you want to set this use <see cref="SingularityGeneratorSystem.SetPower"/>
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float Power = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The power threshold at which this generator will spawn a singularity.
|
||||
/// If you want to set this use <see cref="SingularityGeneratorSystem.SetThreshold"/>
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float Threshold = 16;
|
||||
|
||||
/// <summary>
|
||||
/// Allows the generator to ignore all the failsafe stuff, e.g. when emagged
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool FailsafeDisabled = false;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum distance at which the generator will check for a field at
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float FailsafeDistance = 16;
|
||||
|
||||
/// <summary>
|
||||
/// The prototype ID used to spawn a singularity.
|
||||
/// </summary>
|
||||
[DataField("spawnId", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string? SpawnPrototype = "Singularity";
|
||||
|
||||
/// <summary>
|
||||
/// The masks the raycast should not go through
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int CollisionMask = (int)CollisionGroup.FullTileMask;
|
||||
|
||||
/// <summary>
|
||||
/// Message to use when there's no containment field on cardinal directions
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId ContainmentFailsafeMessage = "comp-generator-failsafe";
|
||||
|
||||
/// <summary>
|
||||
/// For how long the failsafe will cause the generator to stop working and not issue a failsafe warning
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public TimeSpan FailsafeCooldown = TimeSpan.FromSeconds(10);
|
||||
|
||||
/// <summary>
|
||||
/// How long until the generator can issue a failsafe warning again
|
||||
/// </summary>
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
[AutoPausedField]
|
||||
public TimeSpan NextFailsafe = TimeSpan.Zero;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Singularity.Components;
|
||||
|
||||
namespace Content.Shared.Singularity.EntitySystems;
|
||||
|
||||
/// <summary>
|
||||
/// Shared part of SingularitySingularityGeneratorSystem
|
||||
/// </summary>
|
||||
public abstract class SharedSingularityGeneratorSystem : EntitySystem
|
||||
{
|
||||
#region Dependencies
|
||||
[Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
|
||||
#endregion Dependencies
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SingularityGeneratorComponent, GotEmaggedEvent>(OnEmagged);
|
||||
}
|
||||
|
||||
private void OnEmagged(EntityUid uid, SingularityGeneratorComponent component, ref GotEmaggedEvent args)
|
||||
{
|
||||
component.FailsafeDisabled = true;
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
@@ -129,7 +129,6 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
SubscribeAllEvent<StorageInteractWithItemEvent>(OnInteractWithItem);
|
||||
SubscribeAllEvent<StorageSetItemLocationEvent>(OnSetItemLocation);
|
||||
SubscribeAllEvent<StorageInsertItemIntoLocationEvent>(OnInsertItemIntoLocation);
|
||||
SubscribeAllEvent<StorageRemoveItemEvent>(OnRemoveItem);
|
||||
SubscribeAllEvent<StorageSaveItemLocationEvent>(OnSaveItemLocation);
|
||||
|
||||
SubscribeLocalEvent<StorageComponent, GotReclaimedEvent>(OnReclaimed);
|
||||
@@ -639,19 +638,6 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
TrySetItemStorageLocation(item!, storage!, msg.Location);
|
||||
}
|
||||
|
||||
private void OnRemoveItem(StorageRemoveItemEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (!ValidateInput(args, msg.StorageEnt, msg.ItemEnt, out var player, out var storage, out var item))
|
||||
return;
|
||||
|
||||
_adminLog.Add(
|
||||
LogType.Storage,
|
||||
LogImpact.Low,
|
||||
$"{ToPrettyString(player):player} is removing {ToPrettyString(item):item} from {ToPrettyString(storage):storage}");
|
||||
TransformSystem.DropNextTo(item.Owner, player.Owner);
|
||||
Audio.PlayPredicted(storage.Comp.StorageRemoveSound, storage, player, _audioParams);
|
||||
}
|
||||
|
||||
private void OnInsertItemIntoLocation(StorageInsertItemIntoLocationEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (!ValidateInput(args, msg.StorageEnt, msg.ItemEnt, out var player, out var storage, out var item, held: true))
|
||||
|
||||
@@ -169,20 +169,6 @@ namespace Content.Shared.Storage
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class StorageRemoveItemEvent : EntityEventArgs
|
||||
{
|
||||
public readonly NetEntity ItemEnt;
|
||||
|
||||
public readonly NetEntity StorageEnt;
|
||||
|
||||
public StorageRemoveItemEvent(NetEntity itemEnt, NetEntity storageEnt)
|
||||
{
|
||||
ItemEnt = itemEnt;
|
||||
StorageEnt = storageEnt;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class StorageInsertItemIntoLocationEvent : EntityEventArgs
|
||||
{
|
||||
|
||||
@@ -39,7 +39,8 @@ public partial class ListingData : IEquatable<ListingData>
|
||||
other.Categories,
|
||||
other.OriginalCost,
|
||||
other.RestockTime,
|
||||
other.DiscountDownTo
|
||||
other.DiscountDownTo,
|
||||
other.DisableRefund
|
||||
)
|
||||
{
|
||||
|
||||
@@ -63,7 +64,8 @@ public partial class ListingData : IEquatable<ListingData>
|
||||
HashSet<ProtoId<StoreCategoryPrototype>> categories,
|
||||
IReadOnlyDictionary<ProtoId<CurrencyPrototype>, FixedPoint2> originalCost,
|
||||
TimeSpan restockTime,
|
||||
Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> dataDiscountDownTo
|
||||
Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> dataDiscountDownTo,
|
||||
bool disableRefund
|
||||
)
|
||||
{
|
||||
Name = name;
|
||||
@@ -84,6 +86,7 @@ public partial class ListingData : IEquatable<ListingData>
|
||||
OriginalCost = originalCost;
|
||||
RestockTime = restockTime;
|
||||
DiscountDownTo = new Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2>(dataDiscountDownTo);
|
||||
DisableRefund = disableRefund;
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
@@ -194,6 +197,12 @@ public partial class ListingData : IEquatable<ListingData>
|
||||
[DataField]
|
||||
public Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> DiscountDownTo = new();
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to disable refunding for the store when the listing is purchased from it.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool DisableRefund = false;
|
||||
|
||||
public bool Equals(ListingData? listing)
|
||||
{
|
||||
if (listing == null)
|
||||
@@ -287,7 +296,8 @@ public sealed partial class ListingDataWithCostModifiers : ListingData
|
||||
listingData.Categories,
|
||||
listingData.OriginalCost,
|
||||
listingData.RestockTime,
|
||||
listingData.DiscountDownTo
|
||||
listingData.DiscountDownTo,
|
||||
listingData.DisableRefund
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user