diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index 4707a69f1e..bab8dcd237 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -4,6 +4,7 @@ using System.Numerics; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; using Content.Server.Station.Events; +using Content.Shared.Atmos.Components; using Content.Shared.Body.Components; using Content.Shared.CCVar; using Content.Shared.Database; @@ -51,6 +52,7 @@ public sealed partial class ShuttleSystem private float FTLCooldown; public float FTLMassLimit; private TimeSpan _hyperspaceKnockdownTime = TimeSpan.FromSeconds(5); + private const float _ftlThrowForce = 20.0f; /// /// Left-side of the station we're allowed to use @@ -74,6 +76,7 @@ public sealed partial class ShuttleSystem private EntityQuery _bodyQuery; private EntityQuery _immuneQuery; private EntityQuery _statusQuery; + private EntityQuery _movedByPressureQuery; private void InitializeFTL() { @@ -83,6 +86,7 @@ public sealed partial class ShuttleSystem _bodyQuery = GetEntityQuery(); _immuneQuery = GetEntityQuery(); _statusQuery = GetEntityQuery(); + _movedByPressureQuery = GetEntityQuery(); _cfg.OnValueChanged(CCVars.FTLStartupTime, time => DefaultStartupTime = time, true); _cfg.OnValueChanged(CCVars.FTLTravelTime, time => DefaultTravelTime = time, true); @@ -375,7 +379,8 @@ public sealed partial class ShuttleSystem var uid = entity.Owner; var comp = entity.Comp1; var xform = _xformQuery.GetComponent(entity); - DoTheDinosaur(xform); + // Sunrise-Edit + //DoTheDinosaur(xform); comp.State = FTLState.Travelling; var fromMapUid = xform.MapUid; @@ -429,6 +434,10 @@ public sealed partial class ShuttleSystem var wowdio = _audio.PlayPvs(comp.TravelSound, uid); comp.TravelStream = wowdio?.Entity; _audio.SetGridAudio(wowdio); + + // Sunrise-Start + DoTheDinosaur(xform, Direction.South.ToVec()); + // Sunrise-End } /// @@ -441,6 +450,16 @@ public sealed partial class ShuttleSystem comp.StateTime = StartEndTime.FromCurTime(_gameTiming, DefaultArrivalTime); comp.State = FTLState.Arriving; + // Sunrise-Start + // Почему оно здесь а не в UpdateFTLArriving? + // Ну потому что когда шаттл выходит из фтл он телепортируется + // к докам и меняет угол поворота. А вот брошеная сущность все еще летит + // в том направлении когда шаттл был в фтл зоне, + // как итог полет будет не назад или вперед а в бок. + var xform = _xformQuery.GetComponent(entity.Owner); + DoTheDinosaur(xform, Direction.North.ToVec()); + // Sunrise-End + if (entity.Comp1.VisualizerProto != null) { comp.VisualizerEntity = SpawnAttachedTo(entity.Comp1.VisualizerProto, entity.Comp1.TargetCoordinates); @@ -467,7 +486,8 @@ public sealed partial class ShuttleSystem var xform = _xformQuery.GetComponent(uid); var body = _physicsQuery.GetComponent(uid); var comp = entity.Comp1; - DoTheDinosaur(xform); + // Sunrise-Edit + //DoTheDinosaur(xform); _dockSystem.SetDockBolts(entity, false); _physics.SetLinearVelocity(uid, Vector2.Zero, body: body); @@ -610,7 +630,7 @@ public sealed partial class ShuttleSystem /// /// Puts everyone unbuckled on the floor, paralyzed. /// - private void DoTheDinosaur(TransformComponent xform) + private void DoTheDinosaur(TransformComponent xform, Vector2 throwDirection) // Sunrise-Edit { // Get enumeration exceptions from people dropping things if we just paralyze as we go var toKnock = new ValueList(); @@ -626,6 +646,22 @@ public sealed partial class ShuttleSystem _stuns.TryParalyze(child, _hyperspaceKnockdownTime, true, status); + // Sunrise-Start + if (_physicsQuery.TryGetComponent(child, out var physics)) + { + if ((physics.BodyType & BodyType.Static) != 0) + continue; + + _throwing.TryThrow(child, + throwDirection * _ftlThrowForce, + physics, + Transform(child), + _projQuery, + _ftlThrowForce, + playSound: false); + } + // Sunrise-End + // If the guy we knocked down is on a spaced tile, throw them too if (grid != null) TossIfSpaced((xform.GridUid.Value, grid, shuttleBody), child); @@ -667,6 +703,11 @@ public sealed partial class ShuttleSystem if (!_buckleQuery.TryGetComponent(child, out var buckle) || buckle.Buckled) continue; + // Sunrise-Start + if (_movedByPressureQuery.TryComp(child, out var moved) && !moved.Enabled) + continue; + // Sunrise-End + toKnock.Add(child); } } diff --git a/Content.Shared/Buckle/BuckleDoafterEvent.cs b/Content.Shared/Buckle/BuckleDoafterEvent.cs index 268ddfe261..f5c846b38a 100644 --- a/Content.Shared/Buckle/BuckleDoafterEvent.cs +++ b/Content.Shared/Buckle/BuckleDoafterEvent.cs @@ -9,3 +9,11 @@ public sealed partial class BuckleDoAfterEvent : SimpleDoAfterEvent { } + +// Sunrise-Start +[Serializable, NetSerializable] +public sealed partial class UnbuckleDoAfterEvent : SimpleDoAfterEvent +{ + +} +// Sunrise-End diff --git a/Content.Shared/Buckle/Components/BuckleComponent.cs b/Content.Shared/Buckle/Components/BuckleComponent.cs index 1518ccea9b..9b0a157bdf 100644 --- a/Content.Shared/Buckle/Components/BuckleComponent.cs +++ b/Content.Shared/Buckle/Components/BuckleComponent.cs @@ -70,6 +70,11 @@ public sealed partial class BuckleComponent : Component /// Used for client rendering /// [ViewVariables] public int? OriginalDrawDepth; + + // Sunrise-Start + [DataField] + public float UnbuckleDoafterTime = 2f; + // Sunrise-End } public sealed partial class UnbuckleAlertEvent : BaseAlertEvent; diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index 198f9d127a..89ea294c3f 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -60,6 +60,14 @@ public abstract partial class SharedBuckleSystem { BuckleDoafterEarly((uid, comp), ev.Event, ev); }); + + // Sunrise-Start + SubscribeLocalEvent(OnUnbuckleDoafter); + SubscribeLocalEvent>((uid, comp, ev) => + { + UnbuckleDoafterEarly((uid, comp), ev.Event, ev); + }); + // Sunrise-End } private void OnBuckleComponentShutdown(Entity ent, ref ComponentShutdown args) @@ -74,6 +82,11 @@ public abstract partial class SharedBuckleSystem // Prevent people pulling the chair they're on, etc. if (ent.Comp.BuckledTo == args.Pulled && !ent.Comp.PullStrap) args.Cancel(); + + // Sunrise-Start + if (ent.Comp.Buckled) + args.Cancel(); + // Sunrise-End } private void OnBeingPulledAttempt(Entity ent, ref BeingPulledAttemptEvent args) @@ -282,7 +295,7 @@ public abstract partial class SharedBuckleSystem return false; } - if (buckleComp.Buckled && !TryUnbuckle(buckleUid, user, buckleComp)) + if (buckleComp.Buckled) // && !TryUnbuckle(buckleUid, user, buckleComp) Sunrise-Edit { if (popup) { @@ -604,4 +617,27 @@ public abstract partial class SharedBuckleSystem TryBuckle(args.Target.Value, args.User, args.Used.Value, popup: false); } } + + // Sunrise-Start + private void OnUnbuckleDoafter(Entity entity, ref UnbuckleDoAfterEvent args) + { + if (args.Cancelled || args.Handled || args.Target == null) + return; + + args.Handled = TryUnbuckle(args.Target.Value, args.User, popup: false); + } + + private void UnbuckleDoafterEarly(Entity entity, UnbuckleDoAfterEvent args, CancellableEntityEventArgs ev) + { + if (args.Target == null) + return; + + if (TryComp(args.Target, out var targetCuffableComp) && targetCuffableComp.CuffedHandCount > 0 + || _mobState.IsIncapacitated(args.Target.Value)) + { + ev.Cancel(); + TryUnbuckle(args.Target.Value, args.User, popup: false); + } + } + // Sunrise-End } diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs b/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs index 29531ce72b..64996b091b 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs @@ -107,11 +107,26 @@ public abstract partial class SharedBuckleSystem } // Unbuckle others - if (component.BuckledEntities.TryFirstOrNull(out var buckled) && TryUnbuckle(buckled.Value, args.User)) + // Sunrise-Start + if (component.BuckledEntities.TryFirstOrNull(out var buckled)) { - args.Handled = true; - return; + if (CanUnbuckle(buckled.Value, args.User, false)) + { + var doAfterArgs = new DoAfterArgs(EntityManager, args.User, buckle.UnbuckleDoafterTime, new UnbuckleDoAfterEvent(), buckled.Value, buckled.Value) + { + BreakOnMove = true, + BreakOnDamage = true, + AttemptFrequency = AttemptFrequency.EveryTick + }; + + if (_doAfter.TryStartDoAfter(doAfterArgs)) + { + args.Handled = true; + return; + } + } } + // Sunrise-End // TODO BUCKLE add out bool for whether a pop-up was generated or not. } @@ -122,7 +137,31 @@ public abstract partial class SharedBuckleSystem return; if (ent.Comp.BuckledTo != null) - args.Handled = TryUnbuckle(ent!, args.User, popup: true); + { + // Sunrise-Start + if (CanUnbuckle((ent.Owner, ent.Comp), args.User, false)) + { + if (ent.Owner == args.User) + { + args.Handled = TryUnbuckle(ent!, args.User, popup: true); + } + else + { + var doAfterArgs = new DoAfterArgs(EntityManager, args.User, ent.Comp.UnbuckleDoafterTime, new UnbuckleDoAfterEvent(), ent.Owner, ent.Owner) + { + BreakOnMove = true, + BreakOnDamage = true, + AttemptFrequency = AttemptFrequency.EveryTick + }; + + if (_doAfter.TryStartDoAfter(doAfterArgs)) + { + args.Handled = true; + } + } + } + // Sunrise-End + } // TODO BUCKLE add out bool for whether a pop-up was generated or not. } @@ -143,9 +182,31 @@ public abstract partial class SharedBuckleSystem if (!_interaction.InRangeUnobstructed(args.User, args.Target, range: buckledComp.Range)) continue; + // Sunrise-Start + if (!CanUnbuckle(entity, args.User, false)) + continue; + // Sunrise-End + var verb = new InteractionVerb() { - Act = () => TryUnbuckle(entity, args.User, buckleComp: buckledComp), + // Sunrise-Start + Act = () => { + if (entity == args.User) + { + TryUnbuckle(entity, args.User, buckleComp: buckledComp); + } + else + { + var doAfterArgs = new DoAfterArgs(EntityManager, args.User, buckledComp.UnbuckleDoafterTime, new UnbuckleDoAfterEvent(), entity, entity) + { + BreakOnMove = true, + BreakOnDamage = true, + AttemptFrequency = AttemptFrequency.EveryTick + }; + _doAfter.TryStartDoAfter(doAfterArgs); + } + }, + // Sunrise-End Category = VerbCategory.Unbuckle, Text = entity == args.User ? Loc.GetString("verb-self-target-pronoun") @@ -212,7 +273,24 @@ public abstract partial class SharedBuckleSystem InteractionVerb verb = new() { - Act = () => TryUnbuckle(uid, args.User, buckleComp: component), + // Sunrise-Start + Act = () => { + if (uid == args.User) + { + TryUnbuckle(uid, args.User, buckleComp: component); + } + else + { + var doAfterArgs = new DoAfterArgs(EntityManager, args.User, component.UnbuckleDoafterTime, new UnbuckleDoAfterEvent(), uid, uid) + { + BreakOnMove = true, + BreakOnDamage = true, + AttemptFrequency = AttemptFrequency.EveryTick + }; + _doAfter.TryStartDoAfter(doAfterArgs); + } + }, + // Sunrise-End Text = Loc.GetString("verb-categories-unbuckle"), Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png")) }; diff --git a/Content.Shared/CCVar/CCVars.Shuttle.cs b/Content.Shared/CCVar/CCVars.Shuttle.cs index 6ca7f521b1..18f8ed9cb7 100644 --- a/Content.Shared/CCVar/CCVars.Shuttle.cs +++ b/Content.Shared/CCVar/CCVars.Shuttle.cs @@ -86,13 +86,13 @@ public sealed partial class CCVars /// How long a shuttle spends in FTL. /// public static readonly CVarDef FTLTravelTime = - CVarDef.Create("shuttle.travel_time", 60f, CVar.SERVERONLY); + CVarDef.Create("shuttle.travel_time", 30f, CVar.SERVERONLY); // Sunrise-Edit /// /// How long the final stage of FTL before arrival should be. /// public static readonly CVarDef FTLArrivalTime = - CVarDef.Create("shuttle.arrival_time", 20f, CVar.SERVERONLY); + CVarDef.Create("shuttle.arrival_time", 2f, CVar.SERVERONLY); // Sunrise-Edit /// /// How much time needs to pass before a shuttle can FTL again. diff --git a/Content.Shared/Damage/Components/DamageOnHighSpeedImpactComponent.cs b/Content.Shared/Damage/Components/DamageOnHighSpeedImpactComponent.cs index e7f4fdf703..18121e5351 100644 --- a/Content.Shared/Damage/Components/DamageOnHighSpeedImpactComponent.cs +++ b/Content.Shared/Damage/Components/DamageOnHighSpeedImpactComponent.cs @@ -12,7 +12,7 @@ namespace Content.Shared.Damage.Components; public sealed partial class DamageOnHighSpeedImpactComponent : Component { [DataField("minimumSpeed"), ViewVariables(VVAccess.ReadWrite)] - public float MinimumSpeed = 20f; + public float MinimumSpeed = 10f; // Sunrise-Edit [DataField("speedDamageFactor"), ViewVariables(VVAccess.ReadWrite)] public float SpeedDamageFactor = 0.5f; diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index 0f55c99e72..85d1bfdfa0 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -454,6 +454,13 @@ public sealed class PullingSystem : EntitySystem return false; } + // Sunrise-Start + if (TryComp(pullableUid, out var buckleComponent) && buckleComponent.Buckled) + { + return false; + } + // Sunrise-End + var getPulled = new BeingPulledAttemptEvent(puller, pullableUid); RaiseLocalEvent(pullableUid, getPulled, true); var startPull = new StartPullAttemptEvent(puller, pullableUid); diff --git a/Resources/Changelog/ChangelogSunrise.yml b/Resources/Changelog/ChangelogSunrise.yml index 62f7fc990f..785d354afd 100644 --- a/Resources/Changelog/ChangelogSunrise.yml +++ b/Resources/Changelog/ChangelogSunrise.yml @@ -20016,3 +20016,28 @@ type: Tweak id: 1329 time: '2025-08-02T20:54:50.494668+00:00' +- author: VigersRay + changes: + - message: "\u0422\u0435\u043F\u0435\u0440\u044C \u043F\u0440\u0438 \u0437\u0430\ + \u043F\u0443\u0441\u043A\u0435 \u0438 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\ + \u0438\u0438 FTL \u043F\u043E\u043C\u0438\u043C\u043E \u043E\u0433\u043B\u0443\ + \u0448\u0435\u043D\u0438\u044F \u0432\u0441\u0435 \u0441\u0443\u0449\u0435\u0441\ + \u0442\u0432\u0430 \u0431\u0443\u0434\u0443\u0442 \u043E\u0442\u043F\u0440\u0430\ + \u0432\u043B\u0435\u043D\u044B \u0432 \u043F\u043E\u043B\u0435\u0442. \u041D\ + \u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0437\u0430\u0432\ + \u0438\u0441\u0438\u0442 \u043E\u0442 \u0442\u043E\u0440\u043C\u043E\u0436\u0435\ + \u043D\u0438\u044F \u0438\u043B\u0438 \u043D\u0430\u0447\u0430\u043B\u0430 \u0434\ + \u0432\u0438\u0436\u0435\u043D\u0438\u044F." + type: Tweak + - message: "\u0422\u0435\u043F\u0435\u0440\u044C \u043E\u0442\u0441\u0442\u0435\u0433\ + \u0438\u0432\u0430\u043D\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\ + \u0443\u0449\u0435\u0441\u0442\u0432 \u043F\u0440\u043E\u0438\u0441\u0445\u043E\ + \u0434\u0438\u0442 \u0441 \u0434\u0432\u0443\u0445 \u0441\u0435\u043A\u0443\u043D\ + \u0434\u043D\u043E\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043A\u043E\u0439\ + . \u041D\u0438\u043A\u0430\u043A\u0438\u0445 \u0431\u043E\u043B\u044C\u0448\u0435\ + \ \u043E\u0442\u0441\u0442\u0435\u0433\u0438\u0432\u0430\u043D\u0438\u0439 \u0440\ + \u0430\u0434\u0438 \u0437\u0430\u0431\u0430\u0432\u044B \u043F\u0440\u0438 \u0437\ + \u0430\u043F\u0443\u0441\u043A\u0435 \u0448\u0430\u0442\u0442\u043B\u0430." + type: Tweak + id: 1330 + time: '2025-08-03T03:37:52.488647+00:00'