Merge remote-tracking branch 'space-station-14/master'

This commit is contained in:
Ed
2024-04-13 18:59:09 +03:00
74 changed files with 1038 additions and 503 deletions

View File

@@ -24,6 +24,14 @@ public sealed partial class AdvertiseComponent : Component
[DataField]
public int MaximumWait { get; private set; } = 10 * 60;
/// <summary>
/// If true, the delay before the first advertisement (at MapInit) will ignore <see cref="MinimumWait"/>
/// and instead be rolled between 0 and <see cref="MaximumWait"/>. This only applies to the initial delay;
/// <see cref="MinimumWait"/> will be respected after that.
/// </summary>
[DataField]
public bool Prewarm = true;
/// <summary>
/// The identifier for the advertisements pack prototype.
/// </summary>

View File

@@ -37,13 +37,14 @@ public sealed class AdvertiseSystem : EntitySystem
private void OnMapInit(EntityUid uid, AdvertiseComponent advert, MapInitEvent args)
{
RandomizeNextAdvertTime(advert);
var prewarm = advert.Prewarm;
RandomizeNextAdvertTime(advert, prewarm);
_nextCheckTime = MathHelper.Min(advert.NextAdvertisementTime, _nextCheckTime);
}
private void RandomizeNextAdvertTime(AdvertiseComponent advert)
private void RandomizeNextAdvertTime(AdvertiseComponent advert, bool prewarm = false)
{
var minDuration = Math.Max(1, advert.MinimumWait);
var minDuration = prewarm ? 0 : Math.Max(1, advert.MinimumWait);
var maxDuration = Math.Max(minDuration, advert.MaximumWait);
var waitDuration = TimeSpan.FromSeconds(_random.Next(minDuration, maxDuration));

View File

@@ -1,11 +1,16 @@
using System.Globalization;
using System.Linq;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Server.Hands.Systems;
using Content.Server.Inventory;
using Content.Server.Popups;
using Content.Server.Chat.Systems;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.StationRecords;
using Content.Server.StationRecords.Systems;
using Content.Shared.StationRecords;
using Content.Shared.UserInterface;
using Content.Shared.Access.Systems;
using Content.Shared.Bed.Cryostorage;
@@ -32,6 +37,7 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
[Dependency] private readonly ChatSystem _chatSystem = default!;
[Dependency] private readonly ClimbSystem _climb = default!;
[Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
@@ -40,6 +46,7 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly StationJobsSystem _stationJobs = default!;
[Dependency] private readonly StationRecordsSystem _stationRecords = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
@@ -163,26 +170,30 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
{
var comp = ent.Comp;
var cryostorageEnt = ent.Comp.Cryostorage;
var station = _station.GetOwningStation(ent);
var name = Name(ent.Owner);
if (!TryComp<CryostorageComponent>(cryostorageEnt, out var cryostorageComponent))
return;
// if we have a session, we use that to add back in all the job slots the player had.
if (userId != null)
{
foreach (var station in _station.GetStationsSet())
foreach (var uniqueStation in _station.GetStationsSet())
{
if (!TryComp<StationJobsComponent>(station, out var stationJobs))
if (!TryComp<StationJobsComponent>(uniqueStation, out var stationJobs))
continue;
if (!_stationJobs.TryGetPlayerJobs(station, userId.Value, out var jobs, stationJobs))
if (!_stationJobs.TryGetPlayerJobs(uniqueStation, userId.Value, out var jobs, stationJobs))
continue;
foreach (var job in jobs)
{
_stationJobs.TryAdjustJobSlot(station, job, 1, clamp: true);
_stationJobs.TryAdjustJobSlot(uniqueStation, job, 1, clamp: true);
}
_stationJobs.TryRemovePlayerJobs(station, userId.Value, stationJobs);
_stationJobs.TryRemovePlayerJobs(uniqueStation, userId.Value, stationJobs);
}
}
@@ -203,12 +214,33 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
_gameTicker.OnGhostAttempt(mind.Value, false);
}
}
comp.AllowReEnteringBody = false;
_transform.SetParent(ent, PausedMap.Value);
cryostorageComponent.StoredPlayers.Add(ent);
Dirty(ent, comp);
UpdateCryostorageUIState((cryostorageEnt.Value, cryostorageComponent));
AdminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(ent):player} was entered into cryostorage inside of {ToPrettyString(cryostorageEnt.Value)}");
if (!TryComp<StationRecordsComponent>(station, out var stationRecords))
return;
var key = new StationRecordKey(_stationRecords.GetRecordByName(station.Value, name) ?? default(uint), station.Value);
var jobName = "Unknown";
if (_stationRecords.TryGetRecord<GeneralStationRecord>(key, out var entry, stationRecords))
jobName = entry.JobTitle;
_stationRecords.RemoveRecord(key, stationRecords);
_chatSystem.DispatchStationAnnouncement(station.Value,
Loc.GetString(
"earlyleave-cryo-announcement",
("character", name),
("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName))
), Loc.GetString("earlyleave-cryo-sender"),
playDefaultSound: false
);
}
private void HandleCryostorageReconnection(Entity<CryostorageContainedComponent> entity)

View File

@@ -159,7 +159,6 @@ public sealed class PlantHolderSystem : EntitySystem
if (!_botany.TryGetSeed(seeds, out var seed))
return;
float? seedHealth = seeds.HealthOverride;
var name = Loc.GetString(seed.Name);
var noun = Loc.GetString(seed.Noun);
_popup.PopupCursor(Loc.GetString("plant-holder-component-plant-success-message",
@@ -169,9 +168,9 @@ public sealed class PlantHolderSystem : EntitySystem
component.Seed = seed;
component.Dead = false;
component.Age = 1;
if (seedHealth is float realSeedHealth)
if (seeds.HealthOverride != null)
{
component.Health = realSeedHealth;
component.Health = seeds.HealthOverride.Value;
}
else
{
@@ -288,8 +287,18 @@ public sealed class PlantHolderSystem : EntitySystem
}
component.Health -= (_random.Next(3, 5) * 10);
float? healthOverride;
if (component.Harvest)
{
healthOverride = null;
}
else
{
healthOverride = component.Health;
}
component.Seed.Unique = false;
var seed = _botany.SpawnSeedPacket(component.Seed, Transform(args.User).Coordinates, args.User, component.Health);
var seed = _botany.SpawnSeedPacket(component.Seed, Transform(args.User).Coordinates, args.User, healthOverride);
_randomHelper.RandomOffset(seed, 0.25f);
var displayName = Loc.GetString(component.Seed.DisplayName);
_popup.PopupCursor(Loc.GetString("plant-holder-component-take-sample-message",

View File

@@ -9,7 +9,6 @@ using Content.Shared.Damage.Systems;
using Content.Shared.Explosion;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.IdentityManagement;
using Content.Shared.Input;
using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Movement.Pulling.Components;
@@ -17,8 +16,6 @@ using Content.Shared.Movement.Pulling.Events;
using Content.Shared.Movement.Pulling.Systems;
using Content.Shared.Stacks;
using Content.Shared.Throwing;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.GameStates;
using Robust.Shared.Input.Binding;
using Robust.Shared.Map;
@@ -160,7 +157,7 @@ namespace Content.Server.Hands.Systems
continue;
}
QueueDel(hand.HeldEntity.Value);
TryDrop(args.PullerUid, hand, handsComp: component);
break;
}
}

View File

@@ -1,3 +1,4 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;
namespace Content.Server.ImmovableRod;
@@ -36,4 +37,16 @@ public sealed partial class ImmovableRodComponent : Component
/// </summary>
[DataField("destroyTiles")]
public bool DestroyTiles = true;
/// <summary>
/// If true, this will gib & delete bodies
/// </summary>
[DataField]
public bool ShouldGib = true;
/// <summary>
/// Damage done, if not gibbing
/// </summary>
[DataField]
public DamageSpecifier? Damage;
}

View File

@@ -1,9 +1,10 @@
using Content.Server.Body.Systems;
using Content.Server.Polymorph.Components;
using Content.Server.Popups;
using Content.Shared.Body.Components;
using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.Popups;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
@@ -22,6 +23,8 @@ public sealed class ImmovableRodSystem : EntitySystem
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
public override void Update(float frameTime)
{
@@ -64,11 +67,11 @@ public sealed class ImmovableRodSystem : EntitySystem
var vel = component.DirectionOverride.Degrees switch
{
0f => _random.NextVector2(component.MinSpeed, component.MaxSpeed),
_ => xform.WorldRotation.RotateVec(component.DirectionOverride.ToVec()) * _random.NextFloat(component.MinSpeed, component.MaxSpeed)
_ => _transform.GetWorldRotation(uid).RotateVec(component.DirectionOverride.ToVec()) * _random.NextFloat(component.MinSpeed, component.MaxSpeed)
};
_physics.ApplyLinearImpulse(uid, vel, body: phys);
xform.LocalRotation = (vel - xform.WorldPosition).ToWorldAngle() + MathHelper.PiOver2;
xform.LocalRotation = (vel - _transform.GetWorldPosition(uid)).ToWorldAngle() + MathHelper.PiOver2;
}
}
@@ -94,12 +97,28 @@ public sealed class ImmovableRodSystem : EntitySystem
return;
}
// gib em
// dont delete/hurt self if polymoprhed into a rod
if (TryComp<PolymorphedEntityComponent>(uid, out var polymorphed))
{
if (polymorphed.Parent == ent)
return;
}
// gib or damage em
if (TryComp<BodyComponent>(ent, out var body))
{
component.MobCount++;
_popup.PopupEntity(Loc.GetString("immovable-rod-penetrated-mob", ("rod", uid), ("mob", ent)), uid, PopupType.LargeCaution);
if (!component.ShouldGib)
{
if (component.Damage == null)
return;
_damageable.TryChangeDamage(ent, component.Damage, ignoreResistances: true);
return;
}
_bodySystem.GibBody(ent, body: body);
return;
}

View File

@@ -118,10 +118,12 @@ public sealed partial class PolymorphSystem : EntitySystem
private void OnPolymorphActionEvent(Entity<PolymorphableComponent> ent, ref PolymorphActionEvent args)
{
if (!_proto.TryIndex(args.ProtoId, out var prototype))
if (!_proto.TryIndex(args.ProtoId, out var prototype) || args.Handled)
return;
PolymorphEntity(ent, prototype.Configuration);
args.Handled = true;
}
private void OnRevertPolymorphActionEvent(Entity<PolymorphedEntityComponent> ent,

View File

@@ -66,11 +66,16 @@ public sealed class TegNodeGroup : BaseNodeGroup
public override void LoadNodes(List<Node> groupNodes)
{
DebugTools.Assert(groupNodes.Count <= 3, "The TEG has at most 3 parts");
DebugTools.Assert(_entityManager != null);
base.LoadNodes(groupNodes);
if (groupNodes.Count > 3)
{
// Somehow got more TEG parts. Probably shenanigans. Bail.
return;
}
Generator = groupNodes.OfType<TegNodeGenerator>().SingleOrDefault();
if (Generator != null)
{

View File

@@ -5,7 +5,6 @@ using Content.Server.PDA.Ringer;
using Content.Server.Stack;
using Content.Server.Store.Components;
using Content.Shared.Actions;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
using Content.Shared.Hands.EntitySystems;
@@ -99,13 +98,13 @@ public sealed partial class StoreSystem
}
//dictionary for all currencies, including 0 values for currencies on the whitelist
Dictionary<string, FixedPoint2> allCurrency = new();
Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> allCurrency = new();
foreach (var supported in component.CurrencyWhitelist)
{
allCurrency.Add(supported, FixedPoint2.Zero);
if (component.Balance.ContainsKey(supported))
allCurrency[supported] = component.Balance[supported];
if (component.Balance.TryGetValue(supported, out var value))
allCurrency[supported] = value;
}
// TODO: if multiple users are supposed to be able to interact with a single BUI & see different

View File

@@ -1,3 +1,4 @@
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Ensnaring;
using Content.Shared.CombatMode;
@@ -20,7 +21,6 @@ using Content.Shared.Verbs;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
using Robust.Shared.Utility;
using System.Linq;
namespace Content.Server.Strip
{
@@ -111,7 +111,7 @@ namespace Content.Server.Strip
if (TryComp<CombatModeComponent>(user, out var mode) && mode.IsInCombatMode && !openInCombat)
return;
if (TryComp<ActorComponent>(user, out var actor))
if (TryComp<ActorComponent>(user, out var actor) && HasComp<StrippingComponent>(user))
{
if (_userInterfaceSystem.SessionHasOpenUi(strippable, StrippingUiKey.Key, actor.PlayerSession))
return;

View File

@@ -93,6 +93,9 @@ public sealed partial class ActivatableUISystem : EntitySystem
if (component.InHandsOnly)
return;
if (component.AllowedItems != null)
return;
args.Handled = InteractUI(args.User, uid, component);
}
@@ -104,6 +107,9 @@ public sealed partial class ActivatableUISystem : EntitySystem
if (component.RightClickOnly)
return;
if (component.AllowedItems != null)
return;
args.Handled = InteractUI(args.User, uid, component);
}

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using Content.Server.Salvage;
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
using Content.Shared.Clothing;
@@ -42,7 +42,7 @@ public sealed class ArtifactMagnetTriggerSystem : EntitySystem
if (!magXform.Coordinates.TryDistance(EntityManager, xform.Coordinates, out var distance))
continue;
if (distance > trigger.Range)
if (distance > trigger.MagbootRange)
continue;
_toActivate.Add(artifactUid);