Merge branch 'master' into ion-storm-refactor
This commit is contained in:
@@ -28,7 +28,8 @@ namespace Content.Server.Announcements
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = string.Join(' ', new ArraySegment<string>(args, 1, args.Length-1));
|
||||
// Explicit IEnumerable<string> due to overload ambiguity on .NET 9
|
||||
var message = string.Join(' ', (IEnumerable<string>)new ArraySegment<string>(args, 1, args.Length-1));
|
||||
chat.DispatchGlobalAnnouncement(message, args[0], colorOverride: Color.Gold);
|
||||
}
|
||||
shell.WriteLine("Sent!");
|
||||
|
||||
@@ -184,7 +184,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
||||
return;
|
||||
|
||||
var players = _playerManager.Sessions
|
||||
.Where(x => GameTicker.PlayerGameStatuses[x.UserId] == PlayerGameStatus.JoinedGame)
|
||||
.Where(x => GameTicker.PlayerGameStatuses.TryGetValue(x.UserId, out var status) && status == PlayerGameStatus.JoinedGame)
|
||||
.ToList();
|
||||
|
||||
ChooseAntags((uid, component), players, midround: true);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Globalization;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Ghost;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Inventory;
|
||||
@@ -14,6 +14,7 @@ using Content.Shared.Bed.Cryostorage;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Climbing.Systems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.StationRecords;
|
||||
@@ -26,7 +27,6 @@ using Robust.Shared.Containers;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Content.Server.Bed.Cryostorage;
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ public sealed class SeedExtractorSystem : EntitySystem
|
||||
args.User, PopupType.Medium);
|
||||
|
||||
QueueDel(args.Used);
|
||||
args.Handled = true;
|
||||
|
||||
var amount = _random.Next(seedExtractor.BaseMinSeeds, seedExtractor.BaseMaxSeeds + 1);
|
||||
var coords = Transform(uid).Coordinates;
|
||||
|
||||
@@ -424,7 +424,7 @@ public record struct PriceCalculationEvent()
|
||||
[ByRefEvent]
|
||||
public record struct EstimatedPriceCalculationEvent()
|
||||
{
|
||||
public EntityPrototype Prototype;
|
||||
public required EntityPrototype Prototype;
|
||||
|
||||
/// <summary>
|
||||
/// The total price of the entity.
|
||||
|
||||
@@ -82,6 +82,8 @@ public sealed class CrayonSystem : SharedCrayonSystem
|
||||
|
||||
if (component.DeleteEmpty && component.Charges <= 0)
|
||||
UseUpCrayon(uid, args.User);
|
||||
else
|
||||
_uiSystem.ServerSendUiMessage(uid, SharedCrayonComponent.CrayonUiKey.Key, new CrayonUsedMessage(component.SelectedState));
|
||||
}
|
||||
|
||||
private void OnCrayonUse(EntityUid uid, CrayonComponent component, UseInHandEvent args)
|
||||
|
||||
@@ -184,6 +184,6 @@ namespace Content.Server.GameTicking
|
||||
=> UserHasJoinedGame(session.UserId);
|
||||
|
||||
public bool UserHasJoinedGame(NetUserId userId)
|
||||
=> PlayerGameStatuses[userId] == PlayerGameStatus.JoinedGame;
|
||||
=> PlayerGameStatuses.TryGetValue(userId, out var status) && status == PlayerGameStatus.JoinedGame;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ using Content.Server.Spawners.Components;
|
||||
using Content.Server.Speech.Components;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Players;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Roles.Jobs;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Network;
|
||||
@@ -455,71 +455,4 @@ namespace Content.Server.GameTicking
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Server.Mind;
|
||||
using Content.Server.Points;
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Content.Shared.Points;
|
||||
using Content.Shared.Storage;
|
||||
|
||||
@@ -34,10 +34,11 @@ public sealed class GatewayGeneratorSystem : EntitySystem
|
||||
[Dependency] private readonly GatewaySystem _gateway = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
[Dependency] private readonly SharedMapSystem _maps = default!;
|
||||
[Dependency] private readonly SharedSalvageSystem _salvage = default!;
|
||||
[Dependency] private readonly TileSystem _tile = default!;
|
||||
|
||||
[ValidatePrototypeId<DatasetPrototype>]
|
||||
private const string PlanetNames = "names_borer";
|
||||
[ValidatePrototypeId<LocalizedDatasetPrototype>]
|
||||
private const string PlanetNames = "NamesBorer";
|
||||
|
||||
// TODO:
|
||||
// Fix shader some more
|
||||
@@ -102,7 +103,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem
|
||||
var mapId = _mapManager.CreateMap();
|
||||
var mapUid = _mapManager.GetMapEntityId(mapId);
|
||||
|
||||
var gatewayName = SharedSalvageSystem.GetFTLName(_protoManager.Index<DatasetPrototype>(PlanetNames), seed);
|
||||
var gatewayName = _salvage.GetFTLName(_protoManager.Index<LocalizedDatasetPrototype>(PlanetNames), seed);
|
||||
_metadata.SetEntityName(mapUid, gatewayName);
|
||||
|
||||
var origin = new Vector2i(random.Next(-MaxOffset, MaxOffset), random.Next(-MaxOffset, MaxOffset));
|
||||
|
||||
@@ -4,7 +4,6 @@ using Content.Server.DeviceNetwork;
|
||||
using Content.Server.DeviceNetwork.Components;
|
||||
using Content.Server.DeviceNetwork.Systems;
|
||||
using Content.Server.Emp;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Medical.CrewMonitoring;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Station.Systems;
|
||||
@@ -14,8 +13,10 @@ using Content.Shared.Damage;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Medical.SuitSensor;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Verbs;
|
||||
@@ -383,7 +384,7 @@ public sealed class SuitSensorSystem : EntitySystem
|
||||
|
||||
// Get mob total damage crit threshold
|
||||
int? totalDamageThreshold = null;
|
||||
if (_mobThresholdSystem.TryGetThresholdForState(sensor.User.Value, Shared.Mobs.MobState.Critical, out var critThreshold))
|
||||
if (_mobThresholdSystem.TryGetThresholdForState(sensor.User.Value, MobState.Critical, out var critThreshold))
|
||||
totalDamageThreshold = critThreshold.Value.Int();
|
||||
|
||||
// finally, form suit sensor status
|
||||
|
||||
@@ -11,8 +11,8 @@ public sealed partial class PathfindingSystem
|
||||
/// </summary>
|
||||
public record struct BreadthPathArgs()
|
||||
{
|
||||
public Vector2i Start;
|
||||
public List<Vector2i> Ends;
|
||||
public required Vector2i Start;
|
||||
public required List<Vector2i> Ends;
|
||||
|
||||
public bool Diagonals = false;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ public sealed partial class PathfindingSystem
|
||||
public List<Vector2i> Points = new();
|
||||
|
||||
public List<Vector2i> Path = new();
|
||||
public Dictionary<Vector2i, Vector2i> CameFrom;
|
||||
public Dictionary<Vector2i, Vector2i>? CameFrom;
|
||||
}
|
||||
|
||||
public record struct SplinePathArgs(SimplePathArgs Args)
|
||||
|
||||
@@ -84,6 +84,6 @@ public sealed partial class PathfindingSystem
|
||||
|
||||
public float MaxWiden = 7f;
|
||||
|
||||
public List<Vector2i> Path;
|
||||
public required List<Vector2i> Path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
public (bool Success, bool Handled) TryUseUtensil(EntityUid user, EntityUid target, Entity<UtensilComponent> utensil)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent(target, out FoodComponent? food))
|
||||
return (false, true);
|
||||
return (false, false);
|
||||
|
||||
//Prevents food usage with a wrong utensil
|
||||
if ((food.Utensil & utensil.Comp.Types) == 0)
|
||||
|
||||
@@ -53,7 +53,7 @@ public sealed class KillPersonConditionSystem : EntitySystem
|
||||
return;
|
||||
|
||||
// no other humans to kill
|
||||
var allHumans = _mind.GetAliveHumansExcept(args.MindId);
|
||||
var allHumans = _mind.GetAliveHumans(args.MindId);
|
||||
if (allHumans.Count == 0)
|
||||
{
|
||||
args.Cancelled = true;
|
||||
@@ -77,14 +77,14 @@ public sealed class KillPersonConditionSystem : EntitySystem
|
||||
return;
|
||||
|
||||
// no other humans to kill
|
||||
var allHumans = _mind.GetAliveHumansExcept(args.MindId);
|
||||
var allHumans = _mind.GetAliveHumans(args.MindId);
|
||||
if (allHumans.Count == 0)
|
||||
{
|
||||
args.Cancelled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var allHeads = new List<EntityUid>();
|
||||
var allHeads = new HashSet<Entity<MindComponent>>();
|
||||
foreach (var person in allHumans)
|
||||
{
|
||||
if (TryComp<MindComponent>(person, out var mind) && mind.OwnedEntity is { } ent && HasComp<CommandStaffComponent>(ent))
|
||||
|
||||
@@ -314,6 +314,9 @@ public sealed class MoverController : SharedMoverController
|
||||
var linearInput = Vector2.Zero;
|
||||
var brakeInput = 0f;
|
||||
var angularInput = 0f;
|
||||
var linearCount = 0;
|
||||
var brakeCount = 0;
|
||||
var angularCount = 0;
|
||||
|
||||
foreach (var (pilotUid, pilot, _, consoleXform) in pilots)
|
||||
{
|
||||
@@ -322,24 +325,27 @@ public sealed class MoverController : SharedMoverController
|
||||
if (brakes > 0f)
|
||||
{
|
||||
brakeInput += brakes;
|
||||
brakeCount++;
|
||||
}
|
||||
|
||||
if (strafe.Length() > 0f)
|
||||
{
|
||||
var offsetRotation = consoleXform.LocalRotation;
|
||||
linearInput += offsetRotation.RotateVec(strafe);
|
||||
linearCount++;
|
||||
}
|
||||
|
||||
if (rotation != 0f)
|
||||
{
|
||||
angularInput += rotation;
|
||||
angularCount++;
|
||||
}
|
||||
}
|
||||
|
||||
var count = pilots.Count;
|
||||
linearInput /= count;
|
||||
angularInput /= count;
|
||||
brakeInput /= count;
|
||||
// Don't slow down the shuttle if there's someone just looking at the console
|
||||
linearInput /= Math.Max(1, linearCount);
|
||||
angularInput /= Math.Max(1, angularCount);
|
||||
brakeInput /= Math.Max(1, brakeCount);
|
||||
|
||||
// Handle shuttle movement
|
||||
if (brakeInput > 0f)
|
||||
|
||||
@@ -28,7 +28,7 @@ public sealed partial class SalvageSystem
|
||||
var mission = GetMission(_prototypeManager.Index<SalvageDifficultyPrototype>(missionparams.Difficulty), missionparams.Seed);
|
||||
data.NextOffer = _timing.CurTime + mission.Duration + TimeSpan.FromSeconds(1);
|
||||
|
||||
_labelSystem.Label(cdUid, GetFTLName(_prototypeManager.Index<DatasetPrototype>("names_borer"), missionparams.Seed));
|
||||
_labelSystem.Label(cdUid, GetFTLName(_prototypeManager.Index<LocalizedDatasetPrototype>("NamesBorer"), missionparams.Seed));
|
||||
_audio.PlayPvs(component.PrintSound, uid);
|
||||
|
||||
UpdateConsoles((station.Value, data));
|
||||
|
||||
@@ -104,7 +104,9 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
||||
destComp.BeaconsOnly = true;
|
||||
destComp.RequireCoordinateDisk = true;
|
||||
destComp.Enabled = true;
|
||||
_metaData.SetEntityName(mapUid, SharedSalvageSystem.GetFTLName(_prototypeManager.Index<DatasetPrototype>("names_borer"), _missionParams.Seed));
|
||||
_metaData.SetEntityName(
|
||||
mapUid,
|
||||
_entManager.System<SharedSalvageSystem>().GetFTLName(_prototypeManager.Index<LocalizedDatasetPrototype>("NamesBorer"), _missionParams.Seed));
|
||||
_entManager.AddComponent<FTLBeaconComponent>(mapUid);
|
||||
|
||||
// Saving the mission mapUid to a CD is made optional, in case one is somehow made in a process without a CD entity
|
||||
|
||||
@@ -32,7 +32,7 @@ public interface IGridSpawnGroup
|
||||
public float MaximumDistance { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ProtoId<DatasetPrototype>? NameDataset { get; }
|
||||
public ProtoId<LocalizedDatasetPrototype>? NameDataset { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
int MinCount { get; set; }
|
||||
@@ -75,7 +75,7 @@ public sealed class DungeonSpawnGroup : IGridSpawnGroup
|
||||
public float MaximumDistance { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ProtoId<DatasetPrototype>? NameDataset { get; }
|
||||
public ProtoId<LocalizedDatasetPrototype>? NameDataset { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int MinCount { get; set; } = 1;
|
||||
@@ -106,7 +106,7 @@ public sealed class GridSpawnGroup : IGridSpawnGroup
|
||||
|
||||
/// <inheritdoc />
|
||||
public float MaximumDistance { get; }
|
||||
public ProtoId<DatasetPrototype>? NameDataset { get; }
|
||||
public ProtoId<LocalizedDatasetPrototype>? NameDataset { get; }
|
||||
public int MinCount { get; set; } = 1;
|
||||
public int MaxCount { get; set; } = 1;
|
||||
public ComponentRegistry AddComponents { get; set; } = new();
|
||||
|
||||
@@ -19,10 +19,10 @@ using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Parallax.Biomes;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Salvage;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Tiles;
|
||||
|
||||
@@ -208,7 +208,7 @@ public sealed partial class ShuttleSystem
|
||||
|
||||
if (_protoManager.TryIndex(group.NameDataset, out var dataset))
|
||||
{
|
||||
_metadata.SetEntityName(spawned, SharedSalvageSystem.GetFTLName(dataset, _random.Next()));
|
||||
_metadata.SetEntityName(spawned, _salvage.GetFTLName(dataset, _random.Next()));
|
||||
}
|
||||
|
||||
if (group.Hide)
|
||||
|
||||
@@ -8,6 +8,7 @@ using Content.Server.Station.Systems;
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Salvage;
|
||||
using Content.Shared.Shuttles.Systems;
|
||||
using Content.Shared.Throwing;
|
||||
using JetBrains.Annotations;
|
||||
@@ -51,6 +52,7 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedSalvageSystem _salvage = default!;
|
||||
[Dependency] private readonly ShuttleConsoleSystem _console = default!;
|
||||
[Dependency] private readonly StationSystem _station = default!;
|
||||
[Dependency] private readonly StunSystem _stuns = default!;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Radio.Components;
|
||||
using Content.Server.Roles;
|
||||
using Content.Server.Station.Systems;
|
||||
@@ -9,6 +8,7 @@ using Content.Shared.Administration;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Emag.Components;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Roles;
|
||||
@@ -17,6 +17,7 @@ using Content.Shared.Silicons.Laws.Components;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Wires;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
using Content.Server.Singularity.EntitySystems;
|
||||
|
||||
namespace Content.Server.Singularity.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
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("power")]
|
||||
[Access(friends:typeof(SingularityGeneratorSystem))]
|
||||
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("threshold")]
|
||||
[Access(friends:typeof(SingularityGeneratorSystem))]
|
||||
public float Threshold = 16;
|
||||
|
||||
/// <summary>
|
||||
/// The prototype ID used to spawn a singularity.
|
||||
/// </summary>
|
||||
[DataField("spawnId", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string? SpawnPrototype = "Singularity";
|
||||
}
|
||||
@@ -1,14 +1,23 @@
|
||||
using Content.Server.ParticleAccelerator.Components;
|
||||
using Content.Server.Singularity.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Singularity.Components;
|
||||
using Content.Shared.Singularity.EntitySystems;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Singularity.EntitySystems;
|
||||
|
||||
public sealed class SingularityGeneratorSystem : EntitySystem
|
||||
public sealed class SingularityGeneratorSystem : SharedSingularityGeneratorSystem
|
||||
{
|
||||
#region Dependencies
|
||||
[Dependency] private readonly IViewVariablesManager _vvm = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly PhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
#endregion Dependencies
|
||||
|
||||
public override void Initialize()
|
||||
@@ -100,11 +109,37 @@ public sealed class SingularityGeneratorSystem : EntitySystem
|
||||
/// <param name="args">The state of the beginning of the collision.</param>
|
||||
private void HandleParticleCollide(EntityUid uid, ParticleProjectileComponent component, ref StartCollideEvent args)
|
||||
{
|
||||
if (EntityManager.TryGetComponent<SingularityGeneratorComponent>(args.OtherEntity, out var singularityGeneratorComponent))
|
||||
if (!EntityManager.TryGetComponent<SingularityGeneratorComponent>(args.OtherEntity, out var generatorComp))
|
||||
return;
|
||||
|
||||
if (_timing.CurTime < _metadata.GetPauseTime(uid) + generatorComp.NextFailsafe && !generatorComp.FailsafeDisabled)
|
||||
{
|
||||
EntityManager.QueueDeleteEntity(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
var contained = true;
|
||||
if (!generatorComp.FailsafeDisabled)
|
||||
{
|
||||
var transform = Transform(args.OtherEntity);
|
||||
var directions = Enum.GetValues<Direction>().Length;
|
||||
for (var i = 0; i < directions - 1; i += 2) // Skip every other direction, checking only cardinals
|
||||
{
|
||||
if (!CheckContainmentField((Direction)i, new Entity<SingularityGeneratorComponent>(args.OtherEntity, generatorComp), transform))
|
||||
contained = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!contained && !generatorComp.FailsafeDisabled)
|
||||
{
|
||||
generatorComp.NextFailsafe = _timing.CurTime + generatorComp.FailsafeCooldown;
|
||||
PopupSystem.PopupEntity(Loc.GetString("comp-generator-failsafe", ("target", args.OtherEntity)), args.OtherEntity, PopupType.LargeCaution);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPower(
|
||||
args.OtherEntity,
|
||||
singularityGeneratorComponent.Power + component.State switch
|
||||
generatorComp.Power + component.State switch
|
||||
{
|
||||
ParticleAcceleratorPowerState.Standby => 0,
|
||||
ParticleAcceleratorPowerState.Level0 => 1,
|
||||
@@ -113,10 +148,46 @@ public sealed class SingularityGeneratorSystem : EntitySystem
|
||||
ParticleAcceleratorPowerState.Level3 => 8,
|
||||
_ => 0
|
||||
},
|
||||
singularityGeneratorComponent
|
||||
generatorComp
|
||||
);
|
||||
EntityManager.QueueDeleteEntity(uid);
|
||||
}
|
||||
|
||||
EntityManager.QueueDeleteEntity(uid);
|
||||
}
|
||||
#endregion Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether there's a containment field in a given direction away from the generator
|
||||
/// </summary>
|
||||
/// <param name="transform">The transform component of the singularity generator.</param>
|
||||
/// <remarks>Mostly copied from <see cref="ContainmentFieldGeneratorSystem"/> </remarks>
|
||||
private bool CheckContainmentField(Direction dir, Entity<SingularityGeneratorComponent> generator, TransformComponent transform)
|
||||
{
|
||||
var component = generator.Comp;
|
||||
|
||||
var (worldPosition, worldRotation) = _transformSystem.GetWorldPositionRotation(transform);
|
||||
var dirRad = dir.ToAngle() + worldRotation;
|
||||
|
||||
var ray = new CollisionRay(worldPosition, dirRad.ToVec(), component.CollisionMask);
|
||||
var rayCastResults = _physics.IntersectRay(transform.MapID, ray, component.FailsafeDistance, generator, false);
|
||||
var genQuery = GetEntityQuery<ContainmentFieldComponent>();
|
||||
|
||||
RayCastResults? closestResult = null;
|
||||
|
||||
foreach (var result in rayCastResults)
|
||||
{
|
||||
if (genQuery.HasComponent(result.HitEntity))
|
||||
closestResult = result;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (closestResult == null)
|
||||
return false;
|
||||
|
||||
var ent = closestResult.Value.HitEntity;
|
||||
|
||||
// Check that the field can't be moved. The fields' transform parenting is weird, so skip that
|
||||
return TryComp<PhysicsComponent>(ent, out var collidableComponent) && collidableComponent.BodyType == BodyType.Static;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using Content.Server.Access.Systems;
|
||||
using Content.Server.Forensics;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.PDA;
|
||||
using Content.Shared.Preferences;
|
||||
|
||||
@@ -256,6 +256,11 @@ public sealed partial class StoreSystem
|
||||
RaiseLocalEvent(buyer, listing.ProductEvent);
|
||||
}
|
||||
|
||||
if (listing.DisableRefund)
|
||||
{
|
||||
component.RefundAllowed = false;
|
||||
}
|
||||
|
||||
//log dat shit.
|
||||
_admin.Add(LogType.StorePurchase,
|
||||
LogImpact.Low,
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Traits;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
|
||||
namespace Content.Server.Traits;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user