diff --git a/Content.Client/Atmos/Consoles/AtmosAlertsComputerBoundUserInterface.cs b/Content.Client/Atmos/Consoles/AtmosAlertsComputerBoundUserInterface.cs index 08cae979b9..a31eb898fe 100644 --- a/Content.Client/Atmos/Consoles/AtmosAlertsComputerBoundUserInterface.cs +++ b/Content.Client/Atmos/Consoles/AtmosAlertsComputerBoundUserInterface.cs @@ -11,6 +11,8 @@ public sealed class AtmosAlertsComputerBoundUserInterface : BoundUserInterface protected override void Open() { + base.Open(); + _menu = new AtmosAlertsComputerWindow(this, Owner); _menu.OpenCentered(); _menu.OnClose += Close; diff --git a/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs b/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs index 4816ce8c36..b713959f5a 100644 --- a/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs +++ b/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs @@ -41,6 +41,8 @@ namespace Content.Client.Instruments.UI protected override void Open() { + base.Open(); + _instrumentMenu = this.CreateWindow(); _instrumentMenu.Title = EntMan.GetComponent(Owner).EntityName; diff --git a/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs b/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs index 22e5bc452a..2f5b485ba4 100644 --- a/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs +++ b/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs @@ -20,6 +20,8 @@ public sealed class NewsWriterBoundUserInterface : BoundUserInterface protected override void Open() { + base.Open(); + _menu = this.CreateWindow(); _menu.ArticleEditorPanel.PublishButtonPressed += OnPublishButtonPressed; diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs index b1f239cd78..550d0fcdfe 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs @@ -14,6 +14,8 @@ public sealed class CrewMonitoringBoundUserInterface : BoundUserInterface protected override void Open() { + base.Open(); + EntityUid? gridUid = null; var stationName = string.Empty; diff --git a/Content.Client/Nuke/NukeBoundUserInterface.cs b/Content.Client/Nuke/NukeBoundUserInterface.cs index 2e15042373..3cf6a28974 100644 --- a/Content.Client/Nuke/NukeBoundUserInterface.cs +++ b/Content.Client/Nuke/NukeBoundUserInterface.cs @@ -18,6 +18,8 @@ namespace Content.Client.Nuke protected override void Open() { + base.Open(); + _menu = this.CreateWindow(); _menu.OnKeypadButtonPressed += i => diff --git a/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs b/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs index cbc343c06c..2a7c24e96b 100644 --- a/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs +++ b/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs @@ -12,6 +12,8 @@ public sealed class PowerMonitoringConsoleBoundUserInterface : BoundUserInterfac protected override void Open() { + base.Open(); + _menu = this.CreateWindow(); _menu.SetEntity(Owner); _menu.SendPowerMonitoringConsoleMessageAction += SendPowerMonitoringConsoleMessage; diff --git a/Content.Client/Store/Ui/StoreBoundUserInterface.cs b/Content.Client/Store/Ui/StoreBoundUserInterface.cs index 8c48258de0..d8236604bf 100644 --- a/Content.Client/Store/Ui/StoreBoundUserInterface.cs +++ b/Content.Client/Store/Ui/StoreBoundUserInterface.cs @@ -27,6 +27,8 @@ public sealed class StoreBoundUserInterface : BoundUserInterface protected override void Open() { + base.Open(); + _menu = this.CreateWindow(); if (EntMan.TryGetComponent(Owner, out var store)) _menu.Title = Loc.GetString(store.Name); diff --git a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraSetupBoundUi.cs b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraSetupBoundUi.cs index 1880e431ee..cacb25b004 100644 --- a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraSetupBoundUi.cs +++ b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraSetupBoundUi.cs @@ -21,6 +21,8 @@ public sealed class SurveillanceCameraSetupBoundUi : BoundUserInterface protected override void Open() { + base.Open(); + _window = new(); if (_type == SurveillanceCameraSetupUiKey.Router) diff --git a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs index 7ca4dd4b95..eddaaaf54e 100644 --- a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs +++ b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs @@ -31,6 +31,8 @@ public sealed partial class VoiceMaskNameChangeWindow : FancyWindow OnVerbChange?.Invoke((string?) args.Button.GetItemMetadata(args.Id)); SpeechVerbSelector.SelectId(args.Id); }; + + AddVerbs(); } public void ReloadVerbs(IPrototypeManager proto) diff --git a/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleBoundUserInterface.cs b/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleBoundUserInterface.cs index 80c0fc0276..56d2abf18c 100644 --- a/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleBoundUserInterface.cs +++ b/Content.Client/_EE/Supermatter/Consoles/SupermatterConsoleBoundUserInterface.cs @@ -11,6 +11,8 @@ public sealed class SupermatterConsoleBoundUserInterface : BoundUserInterface protected override void Open() { + base.Open(); + _menu = new SupermatterConsoleWindow(this, Owner); _menu.OpenCentered(); _menu.OnClose += Close; diff --git a/Content.Client/_Goobstation/MartialArts/MartialArtsSystem.cs b/Content.Client/_Goobstation/MartialArts/MartialArtsSystem.cs new file mode 100644 index 0000000000..049bc418cf --- /dev/null +++ b/Content.Client/_Goobstation/MartialArts/MartialArtsSystem.cs @@ -0,0 +1,10 @@ +using Content.Shared._Goobstation.MartialArts; + +namespace Content.Client._Goobstation.MartialArts; + +/// +/// This handles... +/// +public sealed class MartialArtsSystem : SharedMartialArtsSystem +{ +} diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index cd02b1d542..c2c6c47377 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -5,6 +5,7 @@ using Content.Server.Chat.Systems; using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.EntityEffects.EffectConditions; using Content.Server.EntityEffects.Effects; +using Content.Shared._Goobstation.MartialArts.Components; // Goobstation - Martial Arts using Content.Server.Popups; using Content.Shared.Alert; using Content.Shared.Atmos; @@ -61,7 +62,11 @@ public sealed class RespiratorSystem : EntitySystem { if(respirator.Saturation < respirator.SuffocationThreshold) return false; - return !TryComp(uid, out var pullable) || pullable.GrabStage != GrabStage.Suffocate; + if (TryComp(uid, out var pullable) + && pullable.GrabStage == GrabStage.Suffocate) + return false; + + return !HasComp(uid); } // Goobstation end private void OnMapInit(Entity ent, ref MapInitEvent args) diff --git a/Content.Server/Stunnable/Systems/StunbatonSystem.cs b/Content.Server/Stunnable/Systems/StunbatonSystem.cs index 43ad2bccd8..42376f53b0 100644 --- a/Content.Server/Stunnable/Systems/StunbatonSystem.cs +++ b/Content.Server/Stunnable/Systems/StunbatonSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Power.Events; using Content.Server.Stunnable.Components; +using Content.Shared._Goobstation.MartialArts; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage.Events; using Content.Shared.Examine; diff --git a/Content.Server/_EE/Supermatter/Systems/SupermatterSystem.cs b/Content.Server/_EE/Supermatter/Systems/SupermatterSystem.cs index 5e9ec4c48a..a29b5049a5 100644 --- a/Content.Server/_EE/Supermatter/Systems/SupermatterSystem.cs +++ b/Content.Server/_EE/Supermatter/Systems/SupermatterSystem.cs @@ -78,6 +78,9 @@ public sealed partial class SupermatterSystem : EntitySystem foreach (var sm in EntityManager.EntityQuery()) { + if (!sm.Activated) + continue; + var uid = sm.Owner; AnnounceCoreDamage(uid, sm); } @@ -99,7 +102,10 @@ public sealed partial class SupermatterSystem : EntitySystem public void OnSupermatterUpdated(EntityUid uid, SupermatterComponent sm, AtmosDeviceUpdateEvent args) { ProcessAtmos(uid, sm, args.dt); - HandleDamage(uid, sm); + + // This prevents SM from delamming due to spacing without activating the SM. + if (sm.Activated) + HandleDamage(uid, sm); if (sm.Damage >= sm.DamageDelaminationPoint || sm.Delamming) HandleDelamination(uid, sm); diff --git a/Content.Server/_Goobstation/MartialArts/MartialArtsSystem.cs b/Content.Server/_Goobstation/MartialArts/MartialArtsSystem.cs new file mode 100644 index 0000000000..d559ff0822 --- /dev/null +++ b/Content.Server/_Goobstation/MartialArts/MartialArtsSystem.cs @@ -0,0 +1,26 @@ +using Content.Server.Chat.Systems; +using Content.Shared.Chat; +using Content.Shared._Goobstation.MartialArts; +using Content.Shared._Goobstation.MartialArts.Components; +using Content.Shared._Goobstation.MartialArts.Events; + +namespace Content.Server._Goobstation.MartialArts; + +/// +/// Just handles carp sayings for now. +/// +public sealed class MartialArtsSystem : SharedMartialArtsSystem +{ + [Dependency] private readonly ChatSystem _chat = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnSleepingCarpSaying); + } + + private void OnSleepingCarpSaying(Entity ent, ref SleepingCarpSaying args) + { + _chat.TrySendInGameICMessage(ent, Loc.GetString(args.Saying), InGameICChatType.Speak, false); + } +} diff --git a/Content.Shared/Damage/Systems/StaminaSystem.cs b/Content.Shared/Damage/Systems/StaminaSystem.cs index d329f1a6bd..111e276376 100644 --- a/Content.Shared/Damage/Systems/StaminaSystem.cs +++ b/Content.Shared/Damage/Systems/StaminaSystem.cs @@ -1,4 +1,6 @@ using System.Linq; +using Content.Shared._Goobstation.MartialArts; +using Content.Shared._Goobstation.MartialArts.Components; using Content.Shared.Administration.Logs; using Content.Shared.Alert; using Content.Shared.CombatMode; @@ -152,6 +154,13 @@ public sealed partial class StaminaSystem : EntitySystem return; } + // Goobstation - Martial Arts + if (TryComp(args.User, out var knowledgeComp) + && TryComp(args.Weapon, out var blockedComp) + && knowledgeComp.MartialArtsForm == blockedComp.Form) + return; + // Goobstation + var ev = new StaminaDamageOnHitAttemptEvent(); RaiseLocalEvent(uid, ref ev); if (ev.Cancelled) diff --git a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs index 95f3cfca7a..fd0f1c4b30 100644 --- a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs +++ b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared._Goobstation.TableSlam; // Goobstation - Table SLam using Content.Shared.Alert; using Content.Shared.Movement.Pulling.Systems; // Goobstation using Robust.Shared.GameStates; @@ -9,7 +10,7 @@ namespace Content.Shared.Movement.Pulling.Components; /// Specifies an entity as being pullable by an entity with /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(Systems.PullingSystem))] +[Access(typeof(Systems.PullingSystem), typeof(TableSlamSystem))] public sealed partial class PullableComponent : Component { /// @@ -57,6 +58,30 @@ public sealed partial class PullableComponent : Component [AutoNetworkedField] public TimeSpan NextEscapeAttempt = TimeSpan.Zero; + + /// + /// If this pullable being tabled. + /// + [DataField, AutoNetworkedField] + public bool BeingTabled = false; + + /// + /// Constant for tabling throw math + /// + [DataField] + public float BasedTabledForceSpeed = 5f; + + /// + /// Stamina damage. taken on tabled + /// + [DataField] + public float TabledStaminaDamage = 40f; + + /// + /// Damage taken on being tabled. + /// + [DataField] + public float TabledDamage = 5f; // Goobstation end /// diff --git a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs index 99c96f384f..fe207ff2ea 100644 --- a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs +++ b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs @@ -1,4 +1,5 @@ -using Content.Shared.Alert; +using Content.Shared._Goobstation.TableSlam; // Goobstation - Table Slam +using Content.Shared.Alert; using Content.Shared.Movement.Pulling.Systems; using Robust.Shared.GameStates; using Robust.Shared.Map; @@ -10,8 +11,8 @@ namespace Content.Shared.Movement.Pulling.Components; /// /// Specifies an entity as being able to pull another entity with /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(PullingSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +[Access(typeof(PullingSystem), typeof(TableSlamSystem))] // Goobstation - Table Slam public sealed partial class PullerComponent : Component { /// @@ -106,7 +107,7 @@ public sealed partial class PullerComponent : Component public float SuffocateGrabStaminaDamage = 10f; [DataField] - public float GrabThrowDamageModifier = 1f; + public float GrabThrowDamageModifier = 2f; [ViewVariables] public List GrabVirtualItems = new(); diff --git a/Content.Shared/Movement/Pulling/Events/CheckGrabOverridesEvent.cs b/Content.Shared/Movement/Pulling/Events/CheckGrabOverridesEvent.cs new file mode 100644 index 0000000000..faf3121eb6 --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/CheckGrabOverridesEvent.cs @@ -0,0 +1,14 @@ +using Content.Shared.Movement.Components; +using Content.Shared.Movement.Pulling.Systems; + +namespace Content.Shared.Movement.Pulling.Events; + +public sealed class CheckGrabOverridesEvent : EntityEventArgs +{ + public CheckGrabOverridesEvent(GrabStage stage) + { + Stage = stage; + } + + public GrabStage Stage { get; set; } +} diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index d71afe4c8d..7b957470ea 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -1,12 +1,13 @@ +using Content.Shared._Goobstation.MartialArts.Events; // Goobstation - Martial Arts +using Content.Shared.Contests; // Goobstation - Grab Intent using System.Diagnostics.CodeAnalysis; -using System.Numerics; +using System.Numerics; // Goobstation - Grab Intent using Content.Shared._White.Grab; // Goobstation using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; using Content.Shared.Alert; using Content.Shared.Buckle.Components; using Content.Shared.CombatMode; // Goobstation -using Content.Shared.Cuffs; // Goobstation using Content.Shared.Cuffs.Components; // Goobstation using Content.Shared.Damage; // Goobstation using Content.Shared.Damage.Systems; // Goobstation @@ -77,11 +78,11 @@ public sealed class PullingSystem : EntitySystem [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly INetManager _netManager = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedVirtualItemSystem _virtualSystem = default!; [Dependency] private readonly GrabThrownSystem _grabThrown = default!; [Dependency] private readonly SharedCombatModeSystem _combatMode = default!; [Dependency] private readonly ThrowingSystem _throwing = default!; + [Dependency] private readonly ContestsSystem _contests = default!; // Goobstation - Grab Intent public override void Initialize() { @@ -106,7 +107,6 @@ public sealed class PullingSystem : EntitySystem SubscribeLocalEvent(OnRefreshMovespeed); SubscribeLocalEvent(OnDropHandItems); SubscribeLocalEvent(OnVirtualItemThrown); // Goobstation - Grab Intent - SubscribeLocalEvent(OnVirtualItemDropAttempt); // Goobstation - Grab Intent SubscribeLocalEvent(OnAddCuffDoAfterEvent); // Goobstation - Grab Intent SubscribeLocalEvent(OnBuckled); @@ -117,7 +117,6 @@ public sealed class PullingSystem : EntitySystem .Bind(ContentKeyFunctions.ReleasePulledObject, InputCmdHandler.FromDelegate(OnReleasePulledObject, handle: false)) .Register(); } - // Goobstation - Grab Intent private void OnAddCuffDoAfterEvent(Entity ent, ref AddCuffDoAfterEvent args) { @@ -129,7 +128,7 @@ public sealed class PullingSystem : EntitySystem && ent.Comp.Pulling != null) { if(_netManager.IsServer) - StopPulling((EntityUid) ent.Comp.Pulling, comp); + StopPulling(ent.Comp.Pulling.Value, comp); } } // Goobstation @@ -281,89 +280,62 @@ public sealed class PullingSystem : EntitySystem component.NextPushTargetChange += args.PausedTime; } - // Goobstation - Grab Intent - private void OnVirtualItemDropAttempt(EntityUid uid, PullerComponent component, VirtualItemDropAttemptEvent args) - { - if (component.Pulling == null) - return; - - if (component.Pulling != args.BlockingEntity) - return; - - if (_timing.CurTime < component.NextStageChange) - { - args.Cancel(); // VirtualItem is NOT being deleted - return; - } - - if (!args.Throw) - { - if (component.GrabStage > GrabStage.No - && TryComp(args.BlockingEntity, out PullableComponent? comp)) - { - TryLowerGrabStage(component.Pulling.Value, uid); - args.Cancel(); // VirtualItem is NOT being deleted - } - } - else - { - if (component.GrabStage <= GrabStage.Soft) - { - TryLowerGrabStage(component.Pulling.Value, uid); - args.Cancel(); // VirtualItem is NOT being deleted - } - } - } - // Goobstation - - private void OnVirtualItemDeleted(EntityUid uid, PullerComponent component, VirtualItemDeletedEvent args) + // Goobstation - Grab Intent Refactor + private void OnVirtualItemDeleted(Entity ent, ref VirtualItemDeletedEvent args) { // If client deletes the virtual hand then stop the pull. - if (component.Pulling == null) + if (ent.Comp.Pulling == null) return; - if (component.Pulling != args.BlockingEntity) - return; - - if (TryComp(args.BlockingEntity, out PullableComponent? comp)) // Goobstation - { - TryLowerGrabStage(component.Pulling.Value, uid);// Goobstation - } - } - - // Goobstation - Grab Intent - private void OnVirtualItemThrown(EntityUid uid, PullerComponent component, VirtualItemThrownEvent args) - { - if (!TryComp(uid, out PhysicsComponent? throwerPhysics) - || !TryComp(args.BlockingEntity, out PhysicsComponent? throweePhysics) - || component.Pulling == null - || component.Pulling != args.BlockingEntity) + if (ent.Comp.Pulling != args.BlockingEntity) return; if (TryComp(args.BlockingEntity, out PullableComponent? comp)) { - if (_combatMode.IsInCombatMode(uid) && - !HasComp(args.BlockingEntity) && - component.GrabStage > GrabStage.Soft) - { - var distanceToCursor = args.Direction.Length(); - var direction = args.Direction.Normalized() * MathF.Min(distanceToCursor, component.ThrowingDistance); - - var damage = new DamageSpecifier(); - damage.DamageDict.Add("Blunt", 5); - - TryStopPull(args.BlockingEntity, comp, uid, true); - _grabThrown.Throw(args.BlockingEntity, uid, direction, - component.GrabThrownSpeed, - component.StaminaDamageOnThrown, - damage * component.GrabThrowDamageModifier, - damage * component.GrabThrowDamageModifier); // Throwing the grabbed person - - _throwing.TryThrow(uid, -direction * throwerPhysics.InvMass); // Throws back the grabber - _audio.PlayPvs(new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg"), uid); - component.NextStageChange.Add(TimeSpan.FromSeconds(2f)); // To avoid grab and throw spamming - } + TryStopPull(ent.Comp.Pulling.Value, comp, ent); } + + foreach (var item in ent.Comp.GrabVirtualItems) + { + if(TryComp(ent, out var virtualItemComponent)) + _virtualSystem.DeleteVirtualItem((item,virtualItemComponent), ent); + } + ent.Comp.GrabVirtualItems.Clear(); + } + // Goobstation - Grab Intent Refactor + + // Goobstation - Grab Intent + private void OnVirtualItemThrown(EntityUid uid, PullerComponent component, VirtualItemThrownEvent args) + { + if (!TryComp(uid, out var throwerPhysics) + || component.Pulling == null + || component.Pulling != args.BlockingEntity) + return; + + if (!TryComp(args.BlockingEntity, out PullableComponent? comp)) + return; + + if (!_combatMode.IsInCombatMode(uid) + || HasComp(args.BlockingEntity) + || component.GrabStage <= GrabStage.Soft) + return; + + var distanceToCursor = args.Direction.Length(); + var direction = args.Direction.Normalized() * MathF.Min(distanceToCursor, component.ThrowingDistance); + + var damage = new DamageSpecifier(); + damage.DamageDict.Add("Blunt", 5); + + TryStopPull(args.BlockingEntity, comp, uid, true); + _grabThrown.Throw(args.BlockingEntity, + uid, + direction, + component.GrabThrownSpeed, + component.StaminaDamageOnThrown, + damage * component.GrabThrowDamageModifier); // Throwing the grabbed person + _throwing.TryThrow(uid, -direction * throwerPhysics.InvMass); // Throws back the grabber + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg"), uid); + component.NextStageChange.Add(TimeSpan.FromSeconds(4f)); // To avoid grab and throw spamming } // Goobstation @@ -419,12 +391,12 @@ public sealed class PullingSystem : EntitySystem args.ModifySpeed(walkMod, sprintMod); break; case GrabStage.Soft: - var softSpeedMod = component.SoftGrabSpeedModifier; - args.ModifySpeed(walkMod * softSpeedMod, sprintMod * softSpeedMod); + var softGrabSpeedMod = component.SoftGrabSpeedModifier; + args.ModifySpeed(walkMod * softGrabSpeedMod, sprintMod * softGrabSpeedMod); break; case GrabStage.Hard: - var hardSpeedMod = component.HardGrabSpeedModifier; - args.ModifySpeed(walkMod * hardSpeedMod, sprintMod * hardSpeedMod); + var hardGrabSpeedModifier = component.HardGrabSpeedModifier; + args.ModifySpeed(walkMod * hardGrabSpeedModifier, sprintMod * hardGrabSpeedModifier); break; case GrabStage.Suffocate: var chokeSpeedMod = component.ChokeGrabSpeedModifier; @@ -443,12 +415,12 @@ public sealed class PullingSystem : EntitySystem args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); break; case GrabStage.Soft: - var softSpeedMod = component.SoftGrabSpeedModifier; - args.ModifySpeed(component.WalkSpeedModifier * softSpeedMod, component.SprintSpeedModifier * softSpeedMod); + var softGrabSpeedMod = component.SoftGrabSpeedModifier; + args.ModifySpeed(component.WalkSpeedModifier * softGrabSpeedMod, component.SprintSpeedModifier * softGrabSpeedMod); break; case GrabStage.Hard: - var hardSpeedMod = component.HardGrabSpeedModifier; - args.ModifySpeed(component.WalkSpeedModifier * hardSpeedMod, component.SprintSpeedModifier * hardSpeedMod); + var hardGrabSpeedModifier = component.HardGrabSpeedModifier; + args.ModifySpeed(component.WalkSpeedModifier * hardGrabSpeedModifier, component.SprintSpeedModifier * hardGrabSpeedModifier); break; case GrabStage.Suffocate: var chokeSpeedMod = component.ChokeGrabSpeedModifier; @@ -460,19 +432,24 @@ public sealed class PullingSystem : EntitySystem } } - private void OnPullableMoveInput(EntityUid uid, PullableComponent component, ref MoveInputEvent args) + // Goobstation - Grab Intent + private void OnPullableMoveInput(Entity ent, ref MoveInputEvent args) { // If someone moves then break their pulling. - if (!component.BeingPulled) + if (!ent.Comp.BeingPulled) return; var entity = args.Entity; + if (ent.Comp.GrabStage == GrabStage.Soft) + TryStopPull(ent, ent, ent); + if (!_blocker.CanMove(entity)) return; - TryStopPull(uid, component, user: uid); + TryStopPull(ent, ent, user: ent); } + // Goobstation private void OnPullableCollisionChange(EntityUid uid, PullableComponent component, ref CollisionChangeEvent args) { @@ -899,6 +876,10 @@ public sealed class PullingSystem : EntitySystem if (!Resolve(puller.Owner, ref puller.Comp)) return false; + // prevent you from grabbing someone else while being grabbed + if (TryComp(puller.Owner, out var pullerAsPullable) && pullerAsPullable.Puller != null) + return false; + if (pullable.Comp.Puller != puller.Owner || puller.Comp.Pulling != pullable.Owner) return false; @@ -919,7 +900,6 @@ public sealed class PullingSystem : EntitySystem if (!_combatMode.IsInCombatMode(puller.Owner)) return false; - // It's blocking stage update, maybe better UX? if (puller.Comp.GrabStage == GrabStage.Suffocate) { @@ -940,6 +920,9 @@ public sealed class PullingSystem : EntitySystem }; var newStage = puller.Comp.GrabStage + nextStageAddition; + var ev = new CheckGrabOverridesEvent(newStage); // guh + RaiseLocalEvent(puller, ev); + newStage = ev.Stage; if (!TrySetGrabStages((puller.Owner, puller.Comp), (pullable.Owner, pullable.Comp), newStage)) return false; @@ -970,7 +953,8 @@ public sealed class PullingSystem : EntitySystem _ => throw new ArgumentOutOfRangeException() }; - pullable.Comp.GrabEscapeChance = puller.Comp.EscapeChances[stage]; + var massModifier = _contests.MassContest(puller, pullable); + pullable.Comp.GrabEscapeChance = Math.Clamp(puller.Comp.EscapeChances[stage] / massModifier, 0f, 1f); _alertsSystem.ShowAlert(puller, puller.Comp.PullingAlert, puller.Comp.PullingAlertSeverity[stage]); _alertsSystem.ShowAlert(pullable, pullable.Comp.PulledAlert, pullable.Comp.PulledAlertAlertSeverity[stage]); @@ -988,6 +972,9 @@ public sealed class PullingSystem : EntitySystem _audio.PlayPvs(new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg"), pullable); + var comboEv = new ComboAttackPerformedEvent(puller.Owner, pullable.Owner, puller.Owner, ComboAttackType.Grab); + RaiseLocalEvent(puller.Owner, comboEv); + Dirty(pullable); Dirty(puller); @@ -1003,51 +990,50 @@ public sealed class PullingSystem : EntitySystem if (puller.Comp.GrabVirtualItemStageCount.TryGetValue(puller.Comp.GrabStage, out var count)) newVirtualItemsCount += count; - if (virtualItemsCount != newVirtualItemsCount) + if (virtualItemsCount == newVirtualItemsCount) + return true; + var delta = newVirtualItemsCount - virtualItemsCount; + + // Adding new virtual items + if (delta > 0) { - var delta = newVirtualItemsCount - virtualItemsCount; - - // Adding new virtual items - if (delta > 0) + for (var i = 0; i < delta; i++) { - for (var i = 0; i < delta; i++) + var emptyHand = _handsSystem.TryGetEmptyHand(puller, out _); + if (!emptyHand) { - var emptyHand = _handsSystem.TryGetEmptyHand(puller, out _); - if (!emptyHand) - { - if (_netManager.IsServer) - _popup.PopupEntity(Loc.GetString("popup-grab-need-hand"), puller, puller, PopupType.Medium); + if (_netManager.IsServer) + _popup.PopupEntity(Loc.GetString("popup-grab-need-hand"), puller, puller, PopupType.Medium); - return false; - } - - if (!_virtualSystem.TrySpawnVirtualItemInHand(pullable, puller.Owner, out var item, true)) - { - // I'm lazy write client code - if (_netManager.IsServer) - _popup.PopupEntity(Loc.GetString("popup-grab-need-hand"), puller, puller, PopupType.Medium); - - return false; - } - - puller.Comp.GrabVirtualItems.Add(item.Value); + return false; } - } - if (delta < 0) - { - for (var i = 0; i < Math.Abs(delta); i++) + if (!_virtualSystem.TrySpawnVirtualItemInHand(pullable, puller.Owner, out var item, true)) { - if (i >= puller.Comp.GrabVirtualItems.Count) - break; + // I'm lazy write client code + if (_netManager.IsServer) + _popup.PopupEntity(Loc.GetString("popup-grab-need-hand"), puller, puller, PopupType.Medium); - var item = puller.Comp.GrabVirtualItems[i]; - puller.Comp.GrabVirtualItems.Remove(item); - QueueDel(item); + return false; } + + puller.Comp.GrabVirtualItems.Add(item.Value); } } + if (delta >= 0) + return true; + for (var i = 0; i < Math.Abs(delta); i++) + { + if (i >= puller.Comp.GrabVirtualItems.Count) + break; + + var item = puller.Comp.GrabVirtualItems[i]; + puller.Comp.GrabVirtualItems.Remove(item); + if(TryComp(item, out var virtualItemComponent)) + _virtualSystem.DeleteVirtualItem((item,virtualItemComponent), puller); + } + return true; } @@ -1067,7 +1053,7 @@ public sealed class PullingSystem : EntitySystem if (_random.Prob(pullable.Comp.GrabEscapeChance)) return true; - pullable.Comp.NextEscapeAttempt = _timing.CurTime.Add(TimeSpan.FromSeconds(1)); + pullable.Comp.NextEscapeAttempt = _timing.CurTime.Add(TimeSpan.FromSeconds(3)); Dirty(pullable.Owner, pullable.Comp); return false; } @@ -1115,6 +1101,7 @@ public sealed class PullingSystem : EntitySystem pullable.Comp.NextEscapeAttempt = _timing.CurTime.Add(TimeSpan.FromSeconds(1f)); Dirty(pullable); + Dirty(puller); if (!ignoreCombatMode && _combatMode.IsInCombatMode(puller.Owner)) { @@ -1148,6 +1135,4 @@ public enum GrabStageDirection Decrease, } -// Goobstation - Grab Intent - // Goobstation diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index 56bbf4c2bf..aaa902eb44 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -155,6 +155,7 @@ public sealed class ThrowingSystem : EntitySystem { Thrower = user, Animate = animated, + }; // if not given, get the default friction value for distance calculation diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index b4cb220841..7a6f563cb1 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; +using Content.Shared._Goobstation.MartialArts.Events; // Goobstation - Martial Arts using Content.Shared._White; using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; @@ -524,6 +525,8 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList); var damageResult = Damageable.TryChangeDamage(target, modifiedDamage, origin:user, ignoreResistances: resistanceBypass, partMultiplier: component.ClickPartDamageMultiplier); + var comboEv = new ComboAttackPerformedEvent(user, target.Value, meleeUid, ComboAttackType.Harm); + RaiseLocalEvent(user, comboEv); if (damageResult is {Empty: false}) { @@ -691,6 +694,9 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem var damageResult = Damageable.TryChangeDamage(entity, modifiedDamage, origin: user, partMultiplier: component.HeavyPartDamageMultiplier); + var comboEv = new ComboAttackPerformedEvent(user, entity, meleeUid, ComboAttackType.HarmLight); + RaiseLocalEvent(user, comboEv); + if (damageResult != null && damageResult.GetTotal() > FixedPoint2.Zero) { // If the target has stamina and is taking blunt damage, they should also take stamina damage based on their blunt to stamina factor @@ -809,6 +815,9 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem return false; } + var comboEv = new ComboAttackPerformedEvent(user, target.Value, meleeUid, ComboAttackType.Disarm); + RaiseLocalEvent(user, comboEv); + if (!TryComp(user, out var combatMode) || combatMode.CanDisarm == false) // WWDP { diff --git a/Content.Shared/_EE/Supermatter/Components/SupermatterComponent.cs b/Content.Shared/_EE/Supermatter/Components/SupermatterComponent.cs index e40fe87ba5..5db4e6da42 100644 --- a/Content.Shared/_EE/Supermatter/Components/SupermatterComponent.cs +++ b/Content.Shared/_EE/Supermatter/Components/SupermatterComponent.cs @@ -19,7 +19,7 @@ public sealed partial class SupermatterComponent : Component /// The SM will only cycle if activated. /// [DataField] - public bool Activated = true; + public bool Activated = false; /// /// The current status of the singularity, used for alert sounds and the monitoring console diff --git a/Content.Shared/_Goobstation/CCVars/CCVars.Goob.cs b/Content.Shared/_Goobstation/CCVar/CCVars.Goob.cs similarity index 100% rename from Content.Shared/_Goobstation/CCVars/CCVars.Goob.cs rename to Content.Shared/_Goobstation/CCVar/CCVars.Goob.cs diff --git a/Content.Shared/_Goobstation/MartialArts/ComboPrototype.cs b/Content.Shared/_Goobstation/MartialArts/ComboPrototype.cs new file mode 100644 index 0000000000..9f1b4e6b8a --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/ComboPrototype.cs @@ -0,0 +1,70 @@ +using Content.Shared._Goobstation.MartialArts.Components; +using Content.Shared._Goobstation.MartialArts.Events; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared._Goobstation.MartialArts; + +[Prototype("combo")] +[Serializable, NetSerializable, DataDefinition] +public sealed partial class ComboPrototype : IPrototype +{ + [IdDataField] public string ID { get; private set; } = default!; + + [DataField(required: true)] + public MartialArtsForms MartialArtsForm; + + [DataField("attacks", required: true)] + public List AttackTypes = new(); + + //[DataField("weapon")] // Will be done later + //public string? WeaponProtoId; + [DataField("event", required: true)] + public object? ResultEvent; + + /// + /// How much extra damage should this move do on perform? + /// + [DataField] + public int ExtraDamage; + + /// + /// Stun time in seconds + /// + [DataField] + public int ParalyzeTime; + + /// + /// How much stamina damage should this move do on perform. + /// + [DataField] + public float StaminaDamage; + + /// + /// Blunt, Slash, etc. + /// + [DataField] + public string DamageType = "Blunt"; + + /// + /// How fast people are thrown on combo + /// + [DataField] + public float ThrownSpeed = 7f; + + /// + /// Name of the move + /// + [DataField(required: true)] + public string Name = string.Empty; + +} + +[Prototype("comboList")] +public sealed partial class ComboListPrototype : IPrototype +{ + [IdDataField] public string ID { get; private init; } = default!; + + [DataField( required: true)] + public List> Combos = new(); +} diff --git a/Content.Shared/_Goobstation/MartialArts/Components/CanPerformComboComponent.cs b/Content.Shared/_Goobstation/MartialArts/Components/CanPerformComboComponent.cs new file mode 100644 index 0000000000..0d9e74e896 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Components/CanPerformComboComponent.cs @@ -0,0 +1,30 @@ +using Content.Shared._Goobstation.MartialArts.Events; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._Goobstation.MartialArts.Components; +[RegisterComponent] +[NetworkedComponent] +public sealed partial class CanPerformComboComponent : Component +{ + [DataField] + public EntityUid? CurrentTarget; + + [DataField] + public ProtoId BeingPerformed; + + [DataField] + public List LastAttacks = new(); + + [DataField] + public List AllowedCombos = new(); + + [DataField] + public List> RoundstartCombos = new(); + + [DataField] + public TimeSpan ResetTime = TimeSpan.Zero; + + [DataField] + public int ConsecutiveGnashes = 0; +} diff --git a/Content.Shared/_Goobstation/MartialArts/Components/GrabStagesOverrideComponent.cs b/Content.Shared/_Goobstation/MartialArts/Components/GrabStagesOverrideComponent.cs new file mode 100644 index 0000000000..5874c3a611 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Components/GrabStagesOverrideComponent.cs @@ -0,0 +1,12 @@ +using Content.Shared.Movement.Pulling.Systems; + +namespace Content.Shared._Goobstation.MartialArts.Components; + +/// +/// Base component for martial arts that override the normal grab stages. +/// Allows martial arts to start at more advanced grab stages like Hard grabs. +/// +public abstract partial class GrabStagesOverrideComponent : Component +{ + public GrabStage StartingStage = GrabStage.Hard; +} diff --git a/Content.Shared/_Goobstation/MartialArts/Components/GrantMartialArtKnowledgeComponent.cs b/Content.Shared/_Goobstation/MartialArts/Components/GrantMartialArtKnowledgeComponent.cs new file mode 100644 index 0000000000..271dea730a --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Components/GrantMartialArtKnowledgeComponent.cs @@ -0,0 +1,44 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._Goobstation.MartialArts.Components; + +public abstract partial class GrantMartialArtKnowledgeComponent : Component +{ + [DataField] + public bool Used; + + [DataField] + public virtual MartialArtsForms MartialArtsForm { get; set; } = MartialArtsForms.CloseQuartersCombat; +} + +[RegisterComponent] +public sealed partial class GrantCqcComponent : GrantMartialArtKnowledgeComponent +{ + [DataField] + public bool IsBlocked; +} + +[RegisterComponent] +public sealed partial class GrantCorporateJudoComponent : GrantMartialArtKnowledgeComponent +{ + [DataField] + public override MartialArtsForms MartialArtsForm { get; set; } = MartialArtsForms.CorporateJudo; +} + +[RegisterComponent] +public sealed partial class GrantSleepingCarpComponent : GrantMartialArtKnowledgeComponent +{ + [DataField] + public override MartialArtsForms MartialArtsForm { get; set; } = MartialArtsForms.SleepingCarp; + + [DataField] + public int Stage = 1; + + public TimeSpan UseAgainTime = TimeSpan.Zero; + + [DataField] + public int MaxUseDelay = 90; + + [DataField] + public int MinUseDelay = 30; +} diff --git a/Content.Shared/_Goobstation/MartialArts/Components/KravMagaComponents.cs b/Content.Shared/_Goobstation/MartialArts/Components/KravMagaComponents.cs new file mode 100644 index 0000000000..a4e1465475 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Components/KravMagaComponents.cs @@ -0,0 +1,78 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._Goobstation.MartialArts.Components; + +/// +/// This is used for... +/// +[RegisterComponent] +public sealed partial class KravMagaActionComponent : Component +{ + [DataField] + public KravMagaMoves Configuration; + + [DataField] + public string Name; + + [DataField] + public float StaminaDamage; + + [DataField] + public int EffectTime; +} + +[RegisterComponent] +public sealed partial class KravMagaComponent : GrabStagesOverrideComponent +{ + [DataField] + public KravMagaMoves? SelectedMove; + + [DataField] + public KravMagaActionComponent? SelectedMoveComp; + + public readonly List BaseKravMagaMoves = new() + { + "ActionLegSweep", + "ActionNeckChop", + "ActionLungPunch", + }; + + public readonly List KravMagaMoveEntities = new() + { + }; + + [DataField] + public int BaseDamage = 5; + + [DataField] + public int DownedDamageModifier = 2; +} +/// +/// Tracks when an entity is silenced through Krav Maga techniques. +/// Prevents the affected entity from using voice-activated abilities or speaking. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class KravMagaSilencedComponent : Component +{ + [DataField] + public TimeSpan SilencedTime = TimeSpan.Zero; +} + +/// +/// Tracks when an entity's breathing is blocked through Krav Maga techniques. +/// May cause suffocation damage over time when integrated with respiration systems. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class KravMagaBlockedBreathingComponent : Component +{ + [DataField] + public TimeSpan BlockedTime = TimeSpan.Zero; +} + +public enum KravMagaMoves +{ + LegSweep, + NeckChop, + LungPunch, +} diff --git a/Content.Shared/_Goobstation/MartialArts/Components/MartialArtsComponents.cs b/Content.Shared/_Goobstation/MartialArts/Components/MartialArtsComponents.cs new file mode 100644 index 0000000000..d15dd16815 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Components/MartialArtsComponents.cs @@ -0,0 +1,61 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._Goobstation.MartialArts.Components; + +[RegisterComponent] +public sealed partial class MartialArtBlockedComponent : Component +{ + [DataField] + public MartialArtsForms Form; +} + +[RegisterComponent] +[NetworkedComponent] +[AutoGenerateComponentState] +public sealed partial class MartialArtsKnowledgeComponent : GrabStagesOverrideComponent +{ + [DataField] + [AutoNetworkedField] + public MartialArtsForms MartialArtsForm = MartialArtsForms.CloseQuartersCombat; + + [DataField] + [AutoNetworkedField] + public int MinRandomDamageModifier; + + [DataField] + [AutoNetworkedField] + public int MaxRandomDamageModifier = 5; + + [DataField] + [AutoNetworkedField] + public FixedPoint2 BaseDamageModifier; + + [DataField] + [AutoNetworkedField] + public bool RandomDamageModifier; + + [DataField] + [AutoNetworkedField] + public ProtoId RoundstartCombos = "CQCMoves"; + + [DataField] + [AutoNetworkedField] + public bool Blocked = false; + + [DataField] + [AutoNetworkedField] + public List RandomSayings = []; + + [DataField] + [AutoNetworkedField] + public List RandomSayingsDowned = []; +} + +public enum MartialArtsForms +{ + CorporateJudo, + CloseQuartersCombat, + SleepingCarp, +} diff --git a/Content.Shared/_Goobstation/MartialArts/Events/CQCEvents.cs b/Content.Shared/_Goobstation/MartialArts/Events/CQCEvents.cs new file mode 100644 index 0000000000..d4af6bbc18 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Events/CQCEvents.cs @@ -0,0 +1,18 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._Goobstation.MartialArts.Events; + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class CqcSlamPerformedEvent : EntityEventArgs; + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class CqcKickPerformedEvent : EntityEventArgs; + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class CqcRestrainPerformedEvent : EntityEventArgs; + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class CqcPressurePerformedEvent : EntityEventArgs; + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class CqcConsecutivePerformedEvent : EntityEventArgs; diff --git a/Content.Shared/_Goobstation/MartialArts/Events/ComboAttackPerformedEvent.cs b/Content.Shared/_Goobstation/MartialArts/Events/ComboAttackPerformedEvent.cs new file mode 100644 index 0000000000..435180c5dc --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Events/ComboAttackPerformedEvent.cs @@ -0,0 +1,30 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._Goobstation.MartialArts.Events; + +/// +/// Raised when a martial arts combo attack is performed. Contains information about +/// the performer, target, weapon used, and the type of combo attack. +/// +public sealed class ComboAttackPerformedEvent( + EntityUid performer, + EntityUid target, + EntityUid weapon, + ComboAttackType type) + : CancellableEntityEventArgs +{ + public EntityUid Performer { get; } = performer; + public EntityUid Target { get; } = target; + public EntityUid Weapon { get; } = weapon; + public ComboAttackType Type { get; } = type; +} + +[Serializable,NetSerializable] +public enum ComboAttackType : byte +{ + Harm, + HarmLight, + Disarm, + Grab, + Hug, +} diff --git a/Content.Shared/_Goobstation/MartialArts/Events/ComboBeingPerformedEvent.cs b/Content.Shared/_Goobstation/MartialArts/Events/ComboBeingPerformedEvent.cs new file mode 100644 index 0000000000..10f1033d05 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Events/ComboBeingPerformedEvent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared._Goobstation.MartialArts.Events; + +[Serializable,NetSerializable] +public sealed class ComboBeingPerformedEvent(ProtoId protoId) : EntityEventArgs +{ + public ProtoId ProtoId = protoId; +} diff --git a/Content.Shared/_Goobstation/MartialArts/Events/JudoEvents.cs b/Content.Shared/_Goobstation/MartialArts/Events/JudoEvents.cs new file mode 100644 index 0000000000..e41ad52835 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Events/JudoEvents.cs @@ -0,0 +1,16 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._Goobstation.MartialArts.Events; +[Serializable, NetSerializable, DataDefinition] +public sealed partial class JudoThrowPerformedEvent : EntityEventArgs; + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class JudoEyePokePerformedEvent : EntityEventArgs; + + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class JudoArmbarPerformedEvent : EntityEventArgs; + + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class JudoGoldenBlastPerformedEvent : EntityEventArgs; diff --git a/Content.Shared/_Goobstation/MartialArts/Events/KravMagaActionEvent.cs b/Content.Shared/_Goobstation/MartialArts/Events/KravMagaActionEvent.cs new file mode 100644 index 0000000000..4c3c20a094 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Events/KravMagaActionEvent.cs @@ -0,0 +1,10 @@ +using Content.Shared.Actions; + +namespace Content.Shared._Goobstation.MartialArts.Events; + +/// +/// This handles selecting your krav maga action +/// +public sealed partial class KravMagaActionEvent : InstantActionEvent +{ +} diff --git a/Content.Shared/_Goobstation/MartialArts/Events/SleepingCarpEvents.cs b/Content.Shared/_Goobstation/MartialArts/Events/SleepingCarpEvents.cs new file mode 100644 index 0000000000..3b89c210aa --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/Events/SleepingCarpEvents.cs @@ -0,0 +1,18 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._Goobstation.MartialArts.Events; + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class SleepingCarpGnashingTeethPerformedEvent : EntityEventArgs; + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class SleepingCarpKneeHaulPerformedEvent : EntityEventArgs; + +[Serializable, NetSerializable, DataDefinition] +public sealed partial class SleepingCarpCrashingWavesPerformedEvent : EntityEventArgs; + +[Serializable,NetSerializable] +public sealed class SleepingCarpSaying(LocId saying) : EntityEventArgs +{ + public LocId Saying = saying; +}; diff --git a/Content.Shared/_Goobstation/MartialArts/MartialArtPrototype.cs b/Content.Shared/_Goobstation/MartialArts/MartialArtPrototype.cs new file mode 100644 index 0000000000..2500452d6e --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/MartialArtPrototype.cs @@ -0,0 +1,36 @@ +using Content.Shared._Goobstation.MartialArts.Components; +using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; + +namespace Content.Shared._Goobstation.MartialArts; + +[Prototype("martialArt")] +public sealed class MartialArtPrototype : IPrototype +{ + [IdDataField] + public string ID { get; private init; } = default!; + + [DataField] + public MartialArtsForms MartialArtsForm = MartialArtsForms.CloseQuartersCombat; + + [DataField] + public int MinRandomDamageModifier; + + [DataField] + public int MaxRandomDamageModifier = 5; + + [DataField] + public FixedPoint2 BaseDamageModifier; + + [DataField] + public bool RandomDamageModifier; + + [DataField] + public ProtoId RoundstartCombos = "CQCMoves"; + + [DataField] + public List RandomSayings = []; + + [DataField] + public List RandomSayingsDowned = []; +} diff --git a/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.CQC.cs b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.CQC.cs new file mode 100644 index 0000000000..8cfe8f7a1b --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.CQC.cs @@ -0,0 +1,186 @@ +using Content.Shared._Goobstation.MartialArts.Components; +using Content.Shared._Goobstation.MartialArts.Events; +using Content.Shared._Shitmed.Targeting; +using Content.Shared.Bed.Sleep; +using Content.Shared.Damage.Components; +using Content.Shared.Examine; +using Content.Shared.IdentityManagement; +using Content.Shared.Interaction.Events; +using Content.Shared.Mobs.Components; +using Content.Shared.Movement.Pulling.Components; +using Robust.Shared.Audio; + +namespace Content.Shared._Goobstation.MartialArts; + +public partial class SharedMartialArtsSystem +{ + private void InitializeCqc() + { + SubscribeLocalEvent(OnCQCSlam); + SubscribeLocalEvent(OnCQCKick); + SubscribeLocalEvent(OnCQCRestrain); + SubscribeLocalEvent(OnCQCPressure); + SubscribeLocalEvent(OnCQCConsecutive); + SubscribeLocalEvent(OnCQCAttackPerformed); + + SubscribeLocalEvent(OnGrantCQCUse); + SubscribeLocalEvent(OnMapInitEvent); + SubscribeLocalEvent(OnGrantCQCExamine); + } + + + #region Generic Methods + + private void OnMapInitEvent(Entity ent, ref MapInitEvent args) + { + if (!HasComp(ent)) + return; + + if (!TryGrant(ent.Comp, ent)) + return; + + if (TryComp(ent, out var knowledge)) + knowledge.Blocked = true; + } + + private void OnGrantCQCUse(Entity ent, ref UseInHandEvent args) + { + if (!_netManager.IsServer) + return; + + if (ent.Comp.Used) + { + _popupSystem.PopupEntity(Loc.GetString("cqc-fail-used", ("manual", Identity.Entity(ent, EntityManager))), + args.User, + args.User); + return; + } + + if (!TryGrant(ent.Comp, args.User)) + return; + _popupSystem.PopupEntity(Loc.GetString("cqc-success-learned"), args.User, args.User); + ent.Comp.Used = true; + } + + private void OnGrantCQCExamine(Entity ent, ref ExaminedEvent args) + { + if (ent.Comp.Used) + args.PushMarkup(Loc.GetString("cqc-manual-used", ("manual", Identity.Entity(ent, EntityManager)))); + } + + private void OnCQCAttackPerformed(Entity ent, ref ComboAttackPerformedEvent args) + { + if (!TryComp(ent, out var knowledgeComponent)) + return; + + if (knowledgeComponent.MartialArtsForm != MartialArtsForms.CloseQuartersCombat) + return; + + if(knowledgeComponent.Blocked) + return; + + switch (args.Type) + { + case ComboAttackType.Disarm: + _stamina.TakeStaminaDamage(args.Target, 25f); + break; + case ComboAttackType.Harm: + if (!TryComp(ent, out var standing) + || !standing.Active) + return; + _stun.TryKnockdown(args.Target, TimeSpan.FromSeconds(5), true); + _standingState.Stand(ent); + break; + } + + + } + + #endregion + + #region Combo Methods + + private void OnCQCSlam(Entity ent, ref CqcSlamPerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out var downed) + || downed) + return; + + DoDamage(ent, target, proto.DamageType, proto.ExtraDamage, out _); + _stun.TryKnockdown(target, TimeSpan.FromSeconds(proto.ParalyzeTime), true); + if (TryComp(target, out var pullable)) + _pulling.TryStopPull(target, pullable, ent, true); + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit3.ogg"), target); + ComboPopup(ent, target, proto.Name); + } + + private void OnCQCKick(Entity ent, ref CqcKickPerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out var downed) + || !downed) + return; + + if (TryComp(target, out var stamina) && stamina.Critical) + { + _status.TryAddStatusEffect(target, "ForcedSleep", TimeSpan.FromSeconds(10), true); + } + + DoDamage(ent, target, proto.DamageType, proto.ExtraDamage, out var damage, TargetBodyPart.Head); + _stamina.TakeStaminaDamage(target, proto.StaminaDamage, source: ent); + + var mapPos = _transform.GetMapCoordinates(ent).Position; + var hitPos = _transform.GetMapCoordinates(target).Position; + var dir = hitPos - mapPos; + dir *= 1f / dir.Length(); + if (TryComp(target, out var pullable)) + _pulling.TryStopPull(target, pullable, ent, true); + _grabThrowing.Throw(target, ent, dir, proto.ThrownSpeed, proto.StaminaDamage / 2, damage); + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit2.ogg"), target); + ComboPopup(ent, target, proto.Name); + } + + private void OnCQCRestrain(Entity ent, ref CqcRestrainPerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out _)) + return; + + _stun.TryKnockdown(target, TimeSpan.FromSeconds(proto.ParalyzeTime), true); + _stamina.TakeStaminaDamage(target, proto.StaminaDamage, source: ent); + } + + private void OnCQCPressure(Entity ent, ref CqcPressurePerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out _)) + return; + + _stamina.TakeStaminaDamage(target, proto.StaminaDamage, source: ent); + if (!_hands.TryGetActiveItem(target, out var activeItem)) + return; + if(!_hands.TryDrop(target, activeItem.Value)) + return; + if (!_hands.TryGetEmptyHand(target, out var emptyHand)) + return; + if(!_hands.TryPickupAnyHand(ent, activeItem.Value)) + return; + _hands.SetActiveHand(ent, emptyHand); + ComboPopup(ent, target, proto.Name); + } + + private void OnCQCConsecutive(Entity ent, ref CqcConsecutivePerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out _)) + return; + + DoDamage(ent, target, proto.DamageType, proto.ExtraDamage, out _); + _stamina.TakeStaminaDamage(target, proto.StaminaDamage, source: ent); + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit1.ogg"), target); + ComboPopup(ent, target, proto.Name); + } + + #endregion +} diff --git a/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.CanPerformCombo.cs b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.CanPerformCombo.cs new file mode 100644 index 0000000000..313a61a116 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.CanPerformCombo.cs @@ -0,0 +1,78 @@ +using System.Linq; +using Content.Shared._Goobstation.MartialArts.Components; +using Content.Shared._Goobstation.MartialArts.Events; +using Content.Shared.Mobs.Components; +using Robust.Shared.Prototypes; + +namespace Content.Shared._Goobstation.MartialArts; + +/// +/// This handles determining if a combo was performed. +/// +public partial class SharedMartialArtsSystem +{ + private void InitializeCanPerformCombo() + { + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnAttackPerformed); + SubscribeLocalEvent(OnComboBeingPerformed); + } + + private void OnMapInit(EntityUid uid, CanPerformComboComponent component, MapInitEvent args) + { + foreach (var item in component.RoundstartCombos) + { + component.AllowedCombos.Add(_proto.Index(item)); + } + } + + private void OnAttackPerformed(EntityUid uid, CanPerformComboComponent component, ComboAttackPerformedEvent args) + { + if (!HasComp(args.Target)) + return; + + if (component.CurrentTarget != null && args.Target != component.CurrentTarget.Value) + { + component.LastAttacks.Clear(); + } + + if (args.Weapon != uid) + { + component.LastAttacks.Clear(); + return; + } + + component.CurrentTarget = args.Target; + component.ResetTime = _timing.CurTime + TimeSpan.FromSeconds(4); + component.LastAttacks.Add(args.Type); + CheckCombo(uid, component); + } + + private void CheckCombo(EntityUid uid, CanPerformComboComponent comp) + { + + foreach (var proto in comp.AllowedCombos) + { + var sum = comp.LastAttacks.Count - proto.AttackTypes.Count; + if (sum < 0) + continue; + + var list = comp.LastAttacks.GetRange(sum, proto.AttackTypes.Count).AsEnumerable(); + var attackList = proto.AttackTypes.AsEnumerable(); + + if (!list.SequenceEqual(attackList) || proto.ResultEvent == null) + continue; + var beingPerformedEv = new ComboBeingPerformedEvent(proto.ID); + var ev = proto.ResultEvent; + RaiseLocalEvent(uid, beingPerformedEv); + RaiseLocalEvent(uid, ev); + comp.LastAttacks.Clear(); + break; + } + } + private void OnComboBeingPerformed(Entity ent, ref ComboBeingPerformedEvent args) + { + ent.Comp.BeingPerformed = args.ProtoId; + Dirty(ent, ent.Comp); + } +} diff --git a/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.CorporateJudo.cs b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.CorporateJudo.cs new file mode 100644 index 0000000000..15c7c0e4ec --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.CorporateJudo.cs @@ -0,0 +1,134 @@ +using Content.Shared._Goobstation.MartialArts.Components; +using Content.Shared._Goobstation.MartialArts.Events; +using Content.Shared.Clothing; +using Content.Shared.Damage; +using Content.Shared.Eye.Blinding.Components; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.StatusEffect; +using Robust.Shared.Audio; + +namespace Content.Shared._Goobstation.MartialArts; + +public partial class SharedMartialArtsSystem +{ + private void InitializeCorporateJudo() + { + SubscribeLocalEvent(OnJudoThrow); + SubscribeLocalEvent(OnJudoEyepoke); + SubscribeLocalEvent(OnJudoArmbar); + + SubscribeLocalEvent(OnGrantCorporateJudo); + SubscribeLocalEvent(OnRemoveCorporateJudo); + //SubscribeLocalEvent(OnJudoGoldenBlast); -- rework + // Wheel throw + // Discombobulate + } + + #region Generic Methods + + private void OnGrantCorporateJudo(Entity ent, ref ClothingGotEquippedEvent args) + { + if (!_netManager.IsServer) + return; + + var user = args.Wearer; + TryGrant(ent.Comp, user); + } + + private void OnRemoveCorporateJudo(Entity ent, ref ClothingGotUnequippedEvent args) + { + var user = args.Wearer; + if (!TryComp(user, out var martialArtsKnowledge)) + return; + + if (martialArtsKnowledge.MartialArtsForm != MartialArtsForms.CorporateJudo) + return; + + RemComp(user); + RemComp(user); + } + + #endregion + + #region Combo Methods + + private void OnJudoThrow(Entity ent, ref JudoThrowPerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out var downed) + || downed) + return; + + _stun.TryKnockdown(target, TimeSpan.FromSeconds(proto.ParalyzeTime), false); + _stamina.TakeStaminaDamage(target, proto.StaminaDamage); + if (TryComp(target, out var pullable)) + _pulling.TryStopPull(target, pullable, ent, true); + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit3.ogg"), target); + ComboPopup(ent, target, proto.Name); + } + + private void OnJudoEyepoke(Entity ent, ref JudoEyePokePerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out _)) + return; + + if (!TryComp(target, out StatusEffectsComponent? status)) + return; + + _status.TryAddStatusEffect(target, + "TemporaryBlindness", + TimeSpan.FromSeconds(2), + true, + status); + _status.TryAddStatusEffect(target, + "BlurryVision", + TimeSpan.FromSeconds(5), + false, + status); + DoDamage(ent, target, proto.DamageType, proto.ExtraDamage, out _); + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit3.ogg"), target); + ComboPopup(ent, target, proto.Name); + } + + private void OnJudoArmbar(Entity ent, ref JudoArmbarPerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out var downed)) + return; + + switch (downed) + { + case false: + var item = _hands.GetActiveItem(target); + if (item != null) + _hands.TryDrop(target, item.Value); + break; + case true: + _stamina.TakeStaminaDamage(target, proto.StaminaDamage); + _stun.TryKnockdown(target, TimeSpan.FromSeconds(proto.ParalyzeTime), false); + break; + } + + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit3.ogg"), target); + ComboPopup(ent, target, proto.Name); + } + + /* Pending Implement + private void OnJudoGoldenBlast(Entity ent, ref JudoGoldenBlastPerformedEvent args) + { + if (!TryUseMartialArt(ent, MartialArtsForms.CorporateJudo, out var target, out var downed)) + return; + + if (downed) + return; + + _stun.TryParalyze(target, TimeSpan.FromSeconds(30), false); + if (TryComp(target, out var pullable)) + _pulling.TryStopPull(target, pullable, ent, true); + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit3.ogg"), target); + } + */ + + #endregion +} diff --git a/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.KravMaga.cs b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.KravMaga.cs new file mode 100644 index 0000000000..148ac30737 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.KravMaga.cs @@ -0,0 +1,109 @@ +using Content.Shared._Goobstation.MartialArts.Components; +using Content.Shared._Goobstation.MartialArts.Events; +using Content.Shared.Damage; +using Content.Shared.Damage.Components; +using Content.Shared.Mobs.Components; +using Content.Shared.Weapons.Melee.Events; + +namespace Content.Shared._Goobstation.MartialArts; + +/// +/// This handles... +/// +public abstract partial class SharedMartialArtsSystem +{ + private void InitializeKravMaga() + { + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnKravMagaAction); + SubscribeLocalEvent(OnMeleeHitEvent); + SubscribeLocalEvent(OnKravMagaShutdown); + } + + private void OnMeleeHitEvent(Entity ent, ref MeleeHitEvent args) + { + if (args.HitEntities.Count <= 0) + return; + + foreach (var hitEntity in args.HitEntities) + { + if (!HasComp(hitEntity)) + continue; + if (!TryComp(hitEntity, out var isDowned)) + continue; + + DoKravMaga(ent, hitEntity, isDowned); + } + } + + private void DoKravMaga(Entity ent, EntityUid hitEntity, RequireProjectileTargetComponent requireProjectileTargetComponent) + { + if (ent.Comp.SelectedMoveComp == null) + return; + var moveComp = ent.Comp.SelectedMoveComp; + + switch (ent.Comp.SelectedMove) + { + case KravMagaMoves.LegSweep: + if(_netManager.IsClient) + return; + _stun.TryParalyze(hitEntity, TimeSpan.FromSeconds(4), true); + break; + case KravMagaMoves.NeckChop: + var comp = EnsureComp(hitEntity); + comp.SilencedTime = _timing.CurTime + TimeSpan.FromSeconds(moveComp.EffectTime); + break; + case KravMagaMoves.LungPunch: + _stamina.TakeStaminaDamage(hitEntity, moveComp.StaminaDamage); + var blockedBreathingComponent = EnsureComp(hitEntity); + blockedBreathingComponent.BlockedTime = _timing.CurTime + TimeSpan.FromSeconds(moveComp.EffectTime); + break; + case null: + var damage = ent.Comp.BaseDamage; + if (requireProjectileTargetComponent.Active) + damage *= ent.Comp.DownedDamageModifier; + + DoDamage(ent.Owner, hitEntity, "Blunt", damage, out _); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + ent.Comp.SelectedMove = null; + ent.Comp.SelectedMoveComp = null; + } + + private void OnKravMagaAction(Entity ent, ref KravMagaActionEvent args) + { + var actionEnt = args.Action.Owner; + if (!TryComp(actionEnt, out var kravActionComp)) + return; + + _popupSystem.PopupClient(Loc.GetString("krav-maga-ready", ("action", kravActionComp.Name)), ent, ent); + ent.Comp.SelectedMove = kravActionComp.Configuration; + ent.Comp.SelectedMoveComp = kravActionComp; + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + if (HasComp(ent)) + return; + foreach (var actionId in ent.Comp.BaseKravMagaMoves) + { + var actions = _actions.AddAction(ent, actionId); + if (actions != null) + ent.Comp.KravMagaMoveEntities.Add(actions.Value); + } + } + + private void OnKravMagaShutdown(Entity ent, ref ComponentShutdown args) + { + if (!TryComp(ent, out var kravMaga)) + return; + + foreach (var action in ent.Comp.KravMagaMoveEntities) + { + _actions.RemoveAction(action); + } + } +} diff --git a/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.SleepingCarp.cs b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.SleepingCarp.cs new file mode 100644 index 0000000000..ea17daa5bd --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.SleepingCarp.cs @@ -0,0 +1,155 @@ +using System.Linq; +using Content.Shared._Goobstation.MartialArts.Components; +using Content.Shared._Goobstation.MartialArts.Events; +using Content.Shared.Damage; +using Content.Shared.Damage.Components; +using Content.Shared.Interaction.Events; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Popups; +using Content.Shared.Weapons.Reflect; +using Robust.Shared.Audio; + +namespace Content.Shared._Goobstation.MartialArts; + +public partial class SharedMartialArtsSystem +{ + private void InitializeSleepingCarp() + { + SubscribeLocalEvent(OnSleepingCarpGnashing); + SubscribeLocalEvent(OnSleepingCarpKneeHaul); + SubscribeLocalEvent(OnSleepingCarpCrashingWaves); + + SubscribeLocalEvent(OnGrantSleepingCarp); + } + + #region Generic Methods + + private void OnGrantSleepingCarp(Entity ent, ref UseInHandEvent args) + { + if (!_netManager.IsServer) + return; + + if (ent.Comp.Used) + return; + if (ent.Comp.UseAgainTime == TimeSpan.Zero) + { + CarpScrollDelay(ent, args.User); + return; + } + + if (_timing.CurTime < ent.Comp.UseAgainTime) + { + _popupSystem.PopupEntity( + Loc.GetString("carp-scroll-waiting"), + ent, + args.User, + PopupType.MediumCaution); + return; + } + + switch (ent.Comp.Stage) + { + case < 3: + CarpScrollDelay(ent, args.User); + break; + case >= 3: + if (!TryGrant(ent.Comp, args.User)) + return; + var userReflect = EnsureComp(args.User); + userReflect.ReflectProb = 1; + userReflect.Spread = 60; + ent.Comp.Used = true; + _popupSystem.PopupEntity( + Loc.GetString("carp-scroll-complete"), + ent, + args.User, + PopupType.LargeCaution); + return; + } + } + + private void CarpScrollDelay(Entity ent, EntityUid user) + { + var time = _random.Next(ent.Comp.MinUseDelay, ent.Comp.MaxUseDelay); + ent.Comp.UseAgainTime = _timing.CurTime + TimeSpan.FromSeconds(time); + ent.Comp.Stage++; + _popupSystem.PopupEntity( + Loc.GetString("carp-scroll-advance"), + ent, + user, + PopupType.Medium); + } + + #endregion + + #region Combo Methods + + private void OnSleepingCarpGnashing(Entity ent, + ref SleepingCarpGnashingTeethPerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out _)) + return; + + if (!TryComp(ent.Owner, out var knowledgeComponent)) + return; + DoDamage(ent, target, proto.DamageType, proto.ExtraDamage + ent.Comp.ConsecutiveGnashes * 5, out _); + ent.Comp.ConsecutiveGnashes++; + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit1.ogg"), target); + if (TryComp(target, out var standing) + && !standing.Active) + { + var saying = + knowledgeComponent.RandomSayings.ElementAt( + _random.Next(knowledgeComponent.RandomSayings.Count)); + var ev = new SleepingCarpSaying(saying); + RaiseLocalEvent(ent, ev); + } + else + { + var saying = + knowledgeComponent.RandomSayingsDowned.ElementAt( + _random.Next(knowledgeComponent.RandomSayingsDowned.Count)); + var ev = new SleepingCarpSaying(saying); + RaiseLocalEvent(ent, ev); + } + } + + private void OnSleepingCarpKneeHaul(Entity ent, + ref SleepingCarpKneeHaulPerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out var downed) + || downed) + return; + + DoDamage(ent, target, proto.DamageType, proto.ExtraDamage, out _); + _stamina.TakeStaminaDamage(target, proto.StaminaDamage); + _stun.TryParalyze(target, TimeSpan.FromSeconds(proto.ParalyzeTime), true); + if (TryComp(target, out var pullable)) + _pulling.TryStopPull(target, pullable, ent, true); + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit3.ogg"), target); + ComboPopup(ent, target, proto.Name); + } + + private void OnSleepingCarpCrashingWaves(Entity ent, + ref SleepingCarpCrashingWavesPerformedEvent args) + { + if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto) + || !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out var downed) + || downed) + return; + + DoDamage(ent, target, proto.DamageType, proto.ExtraDamage, out var damage); + var mapPos = _transform.GetMapCoordinates(ent).Position; + var hitPos = _transform.GetMapCoordinates(target).Position; + var dir = hitPos - mapPos; + if (TryComp(target, out var pullable)) + _pulling.TryStopPull(target, pullable, ent, true); + _grabThrowing.Throw(target, ent, dir, proto.ThrownSpeed, proto.StaminaDamage / 2, damage); + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit2.ogg"), target); + ComboPopup(ent, target, proto.Name); + } + + #endregion +} diff --git a/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.cs b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.cs new file mode 100644 index 0000000000..46a8a7a737 --- /dev/null +++ b/Content.Shared/_Goobstation/MartialArts/SharedMartialArtsSystem.cs @@ -0,0 +1,287 @@ +using Content.Shared._Goobstation.MartialArts.Components; +using Content.Shared._Shitmed.Targeting; +using Content.Shared._White.Grab; +using Content.Shared.Actions; +using Content.Shared.Damage; +using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.IdentityManagement; +using Content.Shared.Movement.Pulling.Events; +using Content.Shared.Movement.Pulling.Systems; +using Content.Shared.Popups; +using Content.Shared.Speech; +using Content.Shared.Standing; +using Content.Shared.StatusEffect; +using Content.Shared.Stunnable; +using Content.Shared.Weapons.Melee; +using Content.Shared.Weapons.Melee.Events; +using Content.Shared.Weapons.Ranged.Events; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Shared._Goobstation.MartialArts; + +/// +/// Handles most of Martial Arts Systems. +/// +public abstract partial class SharedMartialArtsSystem : EntitySystem +{ + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly PullingSystem _pulling = default!; + [Dependency] private readonly StatusEffectsSystem _status = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly StaminaSystem _stamina = default!; + [Dependency] private readonly GrabThrownSystem _grabThrowing = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedStunSystem _stun = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly INetManager _netManager = default!; + [Dependency] private readonly StandingStateSystem _standingState = default!; + + public override void Initialize() + { + base.Initialize(); + InitializeKravMaga(); + InitializeSleepingCarp(); + InitializeCqc(); + InitializeCorporateJudo(); + InitializeCanPerformCombo(); + + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(CheckGrabStageOverride); + SubscribeLocalEvent(OnMeleeHit); + SubscribeLocalEvent(OnShotAttempt); + SubscribeLocalEvent(OnSilencedSpeakAttempt); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out _, out var comp)) + { + if (_timing.CurTime < comp.ResetTime || comp.LastAttacks.Count <= 0) + continue; + comp.LastAttacks.Clear(); + comp.ConsecutiveGnashes = 0; + } + + var kravSilencedQuery = EntityQueryEnumerator(); + while (kravSilencedQuery.MoveNext(out var ent, out var comp)) + { + if (_timing.CurTime < comp.SilencedTime) + continue; + RemComp(ent); + } + + var kravBlockedQuery = EntityQueryEnumerator(); + while (kravBlockedQuery.MoveNext(out var ent, out var comp)) + { + if (_timing.CurTime < comp.BlockedTime) + continue; + RemComp(ent); + } + } + + #region Event Methods + + private void OnMeleeHit(Entity ent, ref MeleeHitEvent args) + { + if (args.Handled) + return; + + if (!ent.Comp.RandomDamageModifier) + return; + + var randomDamage = _random.Next(ent.Comp.MinRandomDamageModifier, ent.Comp.MaxRandomDamageModifier); + var bonusDamageSpec = new DamageSpecifier(); + bonusDamageSpec.DamageDict.Add("Blunt", randomDamage); + args.BonusDamage += bonusDamageSpec; + } + + private void OnShutdown(Entity ent, ref ComponentShutdown args) + { + if(TryComp(ent, out var comboComponent)) + comboComponent.AllowedCombos.Clear(); + } + + private void CheckGrabStageOverride(EntityUid uid, T component, CheckGrabOverridesEvent args) + where T : GrabStagesOverrideComponent + { + if (args.Stage == GrabStage.Soft) + args.Stage = component.StartingStage; + } + + private void OnSilencedSpeakAttempt(Entity ent, ref SpeakAttemptEvent args) + { + _popupSystem.PopupEntity(Loc.GetString("popup-grabbed-cant-speak"), + ent, + ent); // You cant speak while someone is choking you + args.Cancel(); + } + + private void OnShotAttempt(Entity ent, ref ShotAttemptedEvent args) + { + if (ent.Comp.MartialArtsForm != MartialArtsForms.SleepingCarp) + return; + _popupSystem.PopupClient(Loc.GetString("gun-disabled"), ent, ent); + args.Cancel(); + } + + private void ComboPopup(EntityUid user, EntityUid target, string comboName) + { + if (!_netManager.IsServer) + return; + var userName = Identity.Entity(user, EntityManager); + var targetName = Identity.Entity(target, EntityManager); + _popupSystem.PopupEntity(Loc.GetString("martial-arts-action-sender", + ("name", targetName), + ("move", comboName)), + user, + user); + _popupSystem.PopupEntity(Loc.GetString("martial-arts-action-reciever", + ("name", userName), + ("move", comboName)), + target, + target); + } + + #endregion + + #region Helper Methods + + private bool TryGrant(GrantMartialArtKnowledgeComponent comp, EntityUid user) + { + if (!_netManager.IsServer || MetaData(user).EntityLifeStage >= EntityLifeStage.Terminating) + return false; + + if (HasComp(user)) + { + _popupSystem.PopupEntity(Loc.GetString("cqc-fail-knowanother"), user, user); + return false; + } + + if (!HasComp(user)) + { + var canPerformComboComponent = EnsureComp(user); + var martialArtsKnowledgeComponent = EnsureComp(user); + LoadPrototype(user, martialArtsKnowledgeComponent, comp.MartialArtsForm); + martialArtsKnowledgeComponent.Blocked = false; + if (TryComp(user, out var meleeWeaponComponent)) + { + var newDamage = new DamageSpecifier(); + newDamage.DamageDict.Add("Blunt", martialArtsKnowledgeComponent.BaseDamageModifier); + meleeWeaponComponent.Damage += newDamage; + } + Dirty(user, canPerformComboComponent); + return true; + } + + if (!TryComp(user, out var cqc)) + { + _popupSystem.PopupEntity(Loc.GetString("cqc-fail-knowanother"), user, user); + return false; + } + + if (cqc.Blocked && comp.MartialArtsForm == MartialArtsForms.CloseQuartersCombat) + { + _popupSystem.PopupEntity(Loc.GetString("cqc-success-unblocked"), user, user); + cqc.Blocked = false; + comp.Used = true; + return false; + } + + _popupSystem.PopupEntity(Loc.GetString("cqc-fail-already"), user, user); + return false; + } + + private void LoadCombos(ProtoId list, CanPerformComboComponent combo) + { + combo.AllowedCombos.Clear(); + if (!_proto.TryIndex(list, out var comboListPrototype)) + return; + foreach (var item in comboListPrototype.Combos) + { + combo.AllowedCombos.Add(_proto.Index(item)); + } + } + + private void LoadPrototype(EntityUid uid, MartialArtsKnowledgeComponent component, MartialArtsForms name) + { + // just know i hate this and i probably could grab info from the prototype directly from protomanager i was being stupid + // when i originally wrote the code for this clearly. + var combo = EnsureComp(uid); + if (!_proto.TryIndex(name.ToString(), out var martialArtsPrototype)) + return; + component.MartialArtsForm = martialArtsPrototype.MartialArtsForm; + component.RoundstartCombos = martialArtsPrototype.RoundstartCombos; + component.MinRandomDamageModifier = martialArtsPrototype.MinRandomDamageModifier; + component.MaxRandomDamageModifier = martialArtsPrototype.MaxRandomDamageModifier; + component.RandomDamageModifier = martialArtsPrototype.RandomDamageModifier; + component.RandomSayings = martialArtsPrototype.RandomSayings; + component.RandomSayingsDowned = martialArtsPrototype.RandomSayingsDowned; + LoadCombos(martialArtsPrototype.RoundstartCombos, combo); + } + + private bool TryUseMartialArt(Entity ent, + MartialArtsForms form, + out EntityUid target, + out bool downed) + { + target = EntityUid.Invalid; + downed = false; + + if (ent.Comp.CurrentTarget == null) + return false; + + if (!TryComp(ent, out var knowledgeComponent)) + return false; + + if (!TryComp(ent.Comp.CurrentTarget, out var isDowned)) + return false; + + downed = isDowned.Active; + target = ent.Comp.CurrentTarget.Value; + + if (knowledgeComponent.MartialArtsForm == form && !knowledgeComponent.Blocked) + { + return true; + } + + foreach (var entInRange in _lookup.GetEntitiesInRange(ent, 8f)) + { + if (!TryPrototype(entInRange, out var proto) || proto.ID != "DefaultStationBeaconKitchen" || !knowledgeComponent.Blocked) + continue; + return true; + } + + return false; + } + + private void DoDamage(EntityUid ent, + EntityUid target, + string damageType, + int damageAmount, + out DamageSpecifier damage, + TargetBodyPart? targetBodyPart = null) + { + damage = new DamageSpecifier(); + if(!TryComp(ent, out var targetingComponent)) + return; + damage.DamageDict.Add(damageType, damageAmount); + _damageable.TryChangeDamage(target, damage, origin: ent, targetPart: targetBodyPart ?? targetingComponent.Target); + } + + #endregion +} diff --git a/Content.Shared/_Goobstation/TableSlam/PostTabledComponent.cs b/Content.Shared/_Goobstation/TableSlam/PostTabledComponent.cs new file mode 100644 index 0000000000..97cd0ca9ae --- /dev/null +++ b/Content.Shared/_Goobstation/TableSlam/PostTabledComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._Goobstation.TableSlam; + +/// +/// This is used for... +/// +[RegisterComponent] +public sealed partial class PostTabledComponent : Component +{ + [DataField] + public TimeSpan PostTabledShovableTime = TimeSpan.Zero; + + [DataField] + public float ParalyzeChance = 0.35f; +} diff --git a/Content.Shared/_Goobstation/TableSlam/TableSlamSystem.cs b/Content.Shared/_Goobstation/TableSlam/TableSlamSystem.cs new file mode 100644 index 0000000000..a262233517 --- /dev/null +++ b/Content.Shared/_Goobstation/TableSlam/TableSlamSystem.cs @@ -0,0 +1,157 @@ +using System.Linq; +using Content.Shared.Contests; +using Content.Shared._Shitmed.Targeting; +using Content.Shared.Actions.Events; +using Content.Shared.Climbing.Components; +using Content.Shared.CombatMode; +using Content.Shared.Coordinates; +using Content.Shared.Damage; +using Content.Shared.Damage.Events; +using Content.Shared.Damage.Systems; +using Content.Shared.FixedPoint; +using Content.Shared.Interaction; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; +using Content.Shared.Standing; +using Content.Shared.StatusEffect; +using Content.Shared.Stunnable; +using Content.Shared.Throwing; +using Content.Shared.Weapons.Melee; +using Content.Shared.Weapons.Melee.Events; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Shared._Goobstation.TableSlam; + +/// +/// This handles... +/// +public sealed class TableSlamSystem : EntitySystem +{ + [Dependency] private readonly PullingSystem _pullingSystem = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; + [Dependency] private readonly StandingStateSystem _standing = default!; + [Dependency] private readonly ThrowingSystem _throwingSystem = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly StaminaSystem _staminaSystem = default!; + [Dependency] private readonly SharedStunSystem _stunSystem = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly ContestsSystem _contestsSystem = default!; + [Dependency] private readonly IRobustRandom _random = default!; + /// + public override void Initialize() + { + SubscribeLocalEvent(OnMeleeHit); + SubscribeLocalEvent(OnStartCollide); + SubscribeLocalEvent(OnDisarmAttemptEvent); + } + + private void OnDisarmAttemptEvent(Entity ent, ref DisarmAttemptEvent args) + { + if(!_random.Prob(ent.Comp.ParalyzeChance)) + return; + + _stunSystem.TryParalyze(ent, TimeSpan.FromSeconds(3), false); + RemComp(ent); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + var tabledQuery = EntityQueryEnumerator(); + while (tabledQuery.MoveNext(out var uid, out var comp)) + { + if (_gameTiming.CurTime >= comp.PostTabledShovableTime) + RemComp(uid); + } + } + + private void OnMeleeHit(Entity ent, ref MeleeHitEvent args) + { + if (ent.Comp.GrabStage < GrabStage.Suffocate + || ent.Comp.Pulling == null) + return; + + if(!TryComp(ent.Comp.Pulling, out var pullableComponent)) + return; + + if (args.Direction != null) + return; + if (args.HitEntities.Count is > 1 or 0) + return; + + var target = args.HitEntities.ElementAt(0); + if (!HasComp(target)) // checks if its a table. + return; + + var massContest = _contestsSystem.MassContest(ent, ent.Comp.Pulling.Value); + var attemptChance = Math.Clamp(1 * massContest, 0, 1); + var attemptRoundedToNearestQuarter = Math.Round(attemptChance * 4, MidpointRounding.ToEven) / 4; + if(_random.Prob((float) attemptRoundedToNearestQuarter)) // base chance to table slam someone is 1 if your mass ratio is less than 1 then your going to have a harder time slamming somebody. + TryTableSlam((ent.Comp.Pulling.Value, pullableComponent), ent, target); + } + + public void TryTableSlam(Entity ent, Entity pullerEnt, EntityUid tableUid) + { + if(!_transformSystem.InRange(ent.Owner.ToCoordinates(), tableUid.ToCoordinates(), 2f )) + return; + + _standing.Down(ent); + + _pullingSystem.TryStopPull(ent, ent.Comp, pullerEnt, ignoreGrab: true); + _throwingSystem.TryThrow(ent, tableUid.ToCoordinates() , ent.Comp.BasedTabledForceSpeed, animated: false, doSpin: false); + pullerEnt.Comp.NextStageChange = _gameTiming.CurTime.Add(TimeSpan.FromSeconds(3)); // prevent table slamming spam + + if (TryComp(ent, out var tableableComp)) // Checks that the entity being tabled has the TableableComponent + { + tableableComp.BeingTabled = true; + } + else + { + tableableComp = EnsureComp(ent); // Adds the Tableable Component if it doesn't exist + tableableComp.BeingTabled = true; // This shit is so code :skull: + } + } + + private void OnStartCollide(Entity ent, ref StartCollideEvent args) + { + if(!ent.Comp.BeingTabled) + return; + + if (!HasComp(args.OtherEntity)) + return; + + var modifierOnGlassBreak = 1; + if (TryComp(args.OtherEntity, out var glassTableComponent)) + { + _damageableSystem.TryChangeDamage(args.OtherEntity, glassTableComponent.TableDamage, origin: ent, targetPart: TargetBodyPart.Torso); + _damageableSystem.TryChangeDamage(args.OtherEntity, glassTableComponent.ClimberDamage, origin: ent); + modifierOnGlassBreak = 2; + } + else + { + _damageableSystem.TryChangeDamage(ent, + new DamageSpecifier() + { + DamageDict = new Dictionary { { "Blunt", ent.Comp.TabledDamage } }, + }, + targetPart: TargetBodyPart.Torso); + _damageableSystem.TryChangeDamage(ent, + new DamageSpecifier() + { + DamageDict = new Dictionary { { "Blunt", ent.Comp.TabledDamage } }, + }); + } + + _staminaSystem.TakeStaminaDamage(ent, ent.Comp.TabledStaminaDamage); + _stunSystem.TryKnockdown(ent, TimeSpan.FromSeconds(3 * modifierOnGlassBreak), false); + var postTabledComponent = EnsureComp(ent); + postTabledComponent.PostTabledShovableTime = _gameTiming.CurTime.Add(TimeSpan.FromSeconds(3)); + ent.Comp.BeingTabled = false; + + //_audioSystem.PlayPvs("/Audio/Effects/thudswoosh.ogg", uid); + } +} diff --git a/Content.Shared/_Goobstation/TableSlam/TableableComponent.cs b/Content.Shared/_Goobstation/TableSlam/TableableComponent.cs new file mode 100644 index 0000000000..4692c1e60f --- /dev/null +++ b/Content.Shared/_Goobstation/TableSlam/TableableComponent.cs @@ -0,0 +1,32 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._Goobstation.TableSlam; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TableableComponent : Component +{ + /// + /// If this pullable being tabled. + /// + [DataField, AutoNetworkedField] + public bool BeingTabled = false; + + /// + /// Constant for tabling throw math + /// + [DataField] + public float BasedTabledForceSpeed = 5f; + + /// + /// Stamina damage. taken on tabled + /// + [DataField] + public float TabledStaminaDamage = 40f; + + /// + /// Damage taken on being tabled. + /// + [DataField] + public float TabledDamage = 5f; + // Goobstation end +} \ No newline at end of file diff --git a/Content.Shared/_White/Grab/GrabThrownComponent.cs b/Content.Shared/_White/Grab/GrabThrownComponent.cs index a7eadf7e92..d3dbe6c588 100644 --- a/Content.Shared/_White/Grab/GrabThrownComponent.cs +++ b/Content.Shared/_White/Grab/GrabThrownComponent.cs @@ -8,8 +8,6 @@ public sealed partial class GrabThrownComponent : Component { public DamageSpecifier? DamageOnCollide; - public DamageSpecifier? WallDamageOnCollide; - public float? StaminaDamageOnCollide; public List IgnoreEntity = new(); diff --git a/Content.Shared/_White/Grab/GrabThrownSystem.cs b/Content.Shared/_White/Grab/GrabThrownSystem.cs index 1dbce9db2d..b64ff85899 100644 --- a/Content.Shared/_White/Grab/GrabThrownSystem.cs +++ b/Content.Shared/_White/Grab/GrabThrownSystem.cs @@ -8,6 +8,7 @@ using Robust.Shared.Player; using System.Numerics; using Content.Shared._White; using Content.Shared.Standing; +using Robust.Shared.Physics.Components; namespace Content.Shared._White.Grab; @@ -33,33 +34,39 @@ public sealed class GrabThrownSystem : EntitySystem if (_netMan.IsClient) // To avoid effect spam return; - if (!HasComp(ent.Owner)) + if (!HasComp(ent)) { - RemComp(ent.Owner); + RemComp(ent); return; } if (ent.Comp.IgnoreEntity.Contains(args.OtherEntity)) return; - if (!HasComp(ent.Owner)) - RemComp(ent.Owner); + if (!HasComp(ent)) + RemComp(ent); + + if(!TryComp(ent, out var physicsComponent)) + return; ent.Comp.IgnoreEntity.Add(args.OtherEntity); - var speed = args.OurBody.LinearVelocity.Length(); + var velocity = args.OurBody.LinearVelocity.Length(); + var velocitySquared = args.OurBody.LinearVelocity.LengthSquared(); + var mass = physicsComponent.Mass; + var kineticEnergy = 0.5f * mass * velocitySquared; if (ent.Comp.StaminaDamageOnCollide != null) - _stamina.TakeStaminaDamage(ent.Owner, ent.Comp.StaminaDamageOnCollide.Value); + _stamina.TakeStaminaDamage(ent, ent.Comp.StaminaDamageOnCollide.Value); - var damageScale = speed; - - if (ent.Comp.WallDamageOnCollide != null) - _damageable.TryChangeDamage(args.OtherEntity, ent.Comp.WallDamageOnCollide * damageScale); + var kineticEnergyDamage = new DamageSpecifier(); + kineticEnergyDamage.DamageDict.Add("Blunt", 1); + kineticEnergyDamage *= Math.Floor(kineticEnergy / 100) / 2 + 3; + _damageable.TryChangeDamage(args.OtherEntity, kineticEnergyDamage); _layingDown.TryLieDown(args.OtherEntity, behavior: DropHeldItemsBehavior.AlwaysDrop); - _color.RaiseEffect(Color.Red, new List() { ent.Owner }, Filter.Pvs(ent.Owner, entityManager: EntityManager)); + _color.RaiseEffect(Color.Red, new List() { ent }, Filter.Pvs(ent, entityManager: EntityManager)); } private void OnStopThrow(EntityUid uid, GrabThrownComponent comp, StopThrowEvent args) @@ -77,26 +84,23 @@ public sealed class GrabThrownSystem : EntitySystem /// Entity to throw /// Entity that throws /// Direction + /// How fast you fly when thrown /// Stamina damage on collide /// Damage to entity on collide - /// Damage to wall or anything that was hit by entity public void Throw( EntityUid uid, EntityUid thrower, Vector2 vector, float grabThrownSpeed, float? staminaDamage = null, - DamageSpecifier? damageToUid = null, - DamageSpecifier? damageToWall = null) + DamageSpecifier? damageToUid = null) { - _layingDown.TryLieDown(uid, behavior: DropHeldItemsBehavior.AlwaysDrop); - var comp = EnsureComp(uid); comp.StaminaDamageOnCollide = staminaDamage; - comp.DamageOnCollide = damageToUid; - comp.WallDamageOnCollide = damageToWall; comp.IgnoreEntity.Add(thrower); + comp.DamageOnCollide = damageToUid; + _layingDown.TryLieDown(uid, behavior: DropHeldItemsBehavior.AlwaysDrop); _throwing.TryThrow(uid, vector, grabThrownSpeed, animated: false); } } diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index b600909ef4..35e8de6f1c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -12402,3 +12402,83 @@ Entries: id: 6911 time: '2025-03-07T22:45:53.0000000+00:00' url: https://github.com/Simple-Station/Einstein-Engines/pull/1885 +- author: Eagle + changes: + - type: Add + message: >- + Table slamming. Harm a table when you have someone harm choked, see what + happens. + - type: Tweak + message: >- + Grab throw damage to other entities is now based on the thrown entities + kinetic energy. No more mouse wrecking balls. + - type: Tweak + message: You can now escape from a soft grab by just walking away. + - type: Tweak + message: You can no longer grab someone else while your being grabbed. + - type: Tweak + message: Mass now effects grab release attempts. + id: 6912 + time: '2025-03-08T19:49:02.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1889 +- author: VMSolidus + changes: + - type: Add + message: >- + Added a variety of "Shuttle Spawning Airlocks" for mappers to use, which + can make it so that shuttles like the Cargo Shuttle, Pathfinder, etc. + Spawn already docked to the station. + id: 6913 + time: '2025-03-08T20:11:39.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1890 +- author: Timfa2112 + changes: + - type: Add + message: >- + Added extra descriptions to the revolutionary manifesto and the civilian + disabler + - type: Fix + message: Fixed extenddescription on flash + id: 6914 + time: '2025-03-08T21:08:39.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1887 +- author: RadsammyT + changes: + - type: Tweak + message: >- + the Ore Processors now process Lead, Copper, and Aluminum instantly, and + is much faster at processing Tungsten + id: 6915 + time: '2025-03-08T21:11:30.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1873 +- author: Eagle + changes: + - type: Add + message: >- + Added Corporate Judo, CQC, Sleeping Carp, and Krav Maga martial arts + with unique abilities. + - type: Add + message: >- + The Chef has been given Close Quarters Cooking in the Kitchen and Bar. + Tiders beware. + id: 6916 + time: '2025-03-09T00:31:51.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1891 +- author: AlgumCorrupto + changes: + - type: Fix + message: >- + Fixed bug of the painted roboticist airlock displaying the windowed + counterpart instead of the standard one. + id: 6917 + time: '2025-03-09T03:19:17.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1899 +- author: SolarisBirb + changes: + - type: Fix + message: SM no longer starts on round start. + - type: Fix + message: SM will no longer delam from spacing unless it's activated. + id: 6918 + time: '2025-03-09T04:45:00.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1901 diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index a7c4702877..037939d486 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0x6273, 13spacemen, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 2digitman, 4310v343k, 4dplanner, 612git, 778b, Ablankmann, abregado, Absolute-Potato, Acruid, actioninja, actually-reb, ada-please, adamsong, Adeinitas, Admiral-Obvious-001, adrian, Adrian16199, Aerocrux, Aexolott, Aexxie, africalimedrop, afrokada, Agoichi, Ahion, Aidenkrz, Aikakakah, aitorlogedo, ajcm, AJCM-git, AjexRose, Alekshhh, alexkar598, AlexMorgan3817, alexumandxgabriel08x, Alithsko, ALMv1, AlphaQwerty, Altoids1, amylizzle, ancientpower, Andre19926, AndrewEyeke, angelofallars, Anzarot121, Appiah, ar4ill, ArchPigeon, ArchRBX, areitpog, Arendian, arimah, Arkanic, armoks, Arteben, ArthurMousatov, ArtisticRoomba, artur, AruMoon, as334, AsikKEsel, asperger-sind, aspiringlich, aspiringLich, astriloqua, avalon, avghdev, AzzyIsNotHere, BananaFlambe, BasedPugilist, BasedUser, beck-thompson, benev0, BGare, bhespiritu, bingojohnson, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, blitzthesquishy, bloodrizer, Bloody2372, blueDev2, BlueHNT, Boaz1111, BobdaBiscuit, BobTheSleder, boiled-water-tsar, BombasterDS, boogiebogus, botanySupremist, brainfood1183, BramvanZijp, Brandon-Huu, Bribrooo, Bright0, brndd, bryce0110, BubblegumBlue, buletsponge, byondfuckery, c0rigin, c4llv07e, CaasGit, capnsockless, CaptainSqrBeard, Carbonhell, Carolyn3114, Carou02, carteblanche4me, CatTheSystem, Centronias, CerberusWolfie, chairbender, Charlese2, chavonadelal, Cheackraze, cheesePizza2, Chief-Engineer, christhirtle, chromiumboy, Chronophylos, Chubbygummibear, CilliePaint, civilCornball, Clement-O, clyf, Clyybber, CMDR-Piboy314, CodedCrow, Cohnway, cojoke-dot, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, CormosLemming, CrafterKolyan, crazybrain23, creadth, CrigCrag, croilbird, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, DadeKuma, Daemon, daerSeebaer, dahnte, dakamakat, DamianX, DangerRevolution, daniel-cr, DanSAussieITS, Daracke, DarkenedSynergy, Darkenson, DawBla, Daxxi3, dch-GH, Deahaka, dean, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, Deeeeja, deepdarkdepths, degradka, Delete69, deltanedas, DeltaV-Bot, DerbyX, derek, dersheppard, dexlerxd, dffdff2423, dge21, diggy0, digitalic, DinoWattz, DisposableCrewmember42, DJB1gYAPPA, DjfjdfofdjfjD, DocNITE, DoctorBeard, DogZeroX, dolgovmi, dontbetank, Doomsdrayk, dootythefrooty, Dorragon, Doru991, DoubleRiceEddiedd, DoutorWhite, drakewill-CRL, Drayff, dribblydrone, DrMelon, drongood12, DrSingh, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, dukevanity, Dutch-VanDerLinde, dvir001, dylanstrategie, Dynexust, Easypoller, eclips_e, EctoplasmIsGood, eden077, EEASAS, Efruit, efzapa, ElectroSR, elsie, elthundercloud, Emisse, emmafornash, EmoGarbage404, Endecc, eoineoineoin, Erisfiregamer1, ERORR404V1, Errant-4, esguard, estacaoespacialpirata, eugene, Evgencheg, ewokswagger, exincore, exp111, f0x-n3rd, FacePluslll, Fahasor, FairlySadPanda, Fansana, Feluk6174, fenndragon, ficcialfaint, Fiftyllama, Fildrance, FillerVK, FinnishPaladin, FirinMaLazors, Fishfish458, fl-oz, Flareguy, FluffiestFloof, FluffMe, FluidRock, flybik, flyingkarii, FoLoKe, fooberticus, ForestNoises, forgotmyotheraccount, forkeyboards, forthbridge, Fortune117, Fouin, foxhorn, FoxxoTrystan, freeman2651, freeze2222, Froffy025, Fromoriss, froozigiusz, FrostMando, FryOfDestiny, FungiFellow, GalacticChimp, gamer3107, Gaxeer, gbasood, gcoremans, Geekyhobo, genderGeometries, GeneralGaws, Genkail, geraeumig, Ghagliiarghii, ghost581x, Git-Nivrak, gituhabu, GlassEclipse, gluesniffler, GNF54, GNUtopia, Golinth, GoodWheatley, gradientvera, graevy, GraniteSidewalk, GreaseMonk, greenrock64, greggthefather, GreyMario, GTRsound, Guess-My-Name, gusxyz, h3half, Haltell, Hanzdegloker, Hardly3D, harikattar, Hebi, Henry, HerCoyote23, hiucko, Hmeister-fake, Hmeister-real, hobnob, HoidC, Holinka4ever, holyssss, HoofedEar, Hoolny, hord-brayden, hubismal, Hugal31, Huxellberger, Hyenh, i-justuser-i, iacore, IamVelcroboy, icekot8, icesickleone, Ichaie, iczero, iglov, igorsaux, ike709, illersaver, Illiux, Ilushkins33, Ilya246, IlyaElDunaev, indeano, Injazz, Insineer, IntegerTempest, Interrobang01, Intoxicating-Innocence, IProduceWidgets, ItsMeThom, Itzbenz, Jackal298, Jackrost, jacksonzck, Jackw2As, jamessimo, janekvap, Jark255, Jaskanbe, JasperJRoth, jerryimmouse, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JimGamemaster, jimmy12or, JIPDawg, jjtParadox, JohnGinnane, johnku1, joshepvodka, Jrpl, jukereise, juliangiebel, juniwoofs, justart1m, JustCone14, justin, justintether, JustinTrotter, justtne, K-Dynamic, k3yw, Kadeo64, KaiShibaa, kalane15, kalanosh, Kanashi-Panda, Keelin, Keer-Sar, KEEYNy, keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, Kimpes, KingFroozy, kira-er, Kirillcas, Kistras, Kit0vras, KittenColony, klaypexx, Kmc2000, Ko4ergaPunk, kognise, komunre, KonstantinAngelov, koteq, Kr8art, Krunklehorn, Kukutis96513, Kupie, kxvvv, Kyoth25f, kzhanik, lajolico, Lamrr, LankLTE, laok233, lapatison, larryrussian, lawdog4817, Lazzi0706, leander-0, leonardo-dabepis, leonsfriedrich, lettern, LetterN, Level10Cybermancer, LEVELcat, lever1209, Lgibb18, LightVillet, liltenhead, LinkUyx, LittleBuilderJane, lizelive, lleftTheDragon, localcc, Lomcastar, lonoferars, LordCarve, LordEclipse, LovelyLophi, luckyshotpictures, LudwigVonChesterfield, Lukasz825700516, Lumminal, lunarcomets, luringens, lvvova1, Lyndomen, lzimann, lzk228, M3739, mac6na6na, MACMAN2003, Macoron, magicalus, magmodius, MagnusCrowe, malchanceux, MaloTV, ManelNavola, Mangohydra, marboww, Markek1, Matz05, max, MaxNox7, MehimoNemo, MeltedPixel, MemeProof, MendaxxDev, Menshin, Mephisto72, Mervill, metalgearsloth, mhamsterr, michaelcu, micheel665, Mike32oz, MilenVolf, milon, MilonPL, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, MjrLandWhale, MLGTASTICa, Mnemotechnician, moderatelyaware, mokiros, Moneyl, Monotheonist, Moomoobeef, moony, Morb0, mr-bo-jangles, Mr0maks, MrFippik, musicmanvr, MWKane, Myakot, Myctai, N3X15, nails-n-tape, Nairodian, Naive817, namespace-Memory, Nannek, NeLepus, neuPanda, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, NIXC, NkoKirkto, nmajask, noctyrnal, nok-ko, NonchalantNoob, NoobyLegion, not-gavnaed, notafet, notquitehadouken, noudoit, noverd, NuclearWinter, nukashimika, nuke-haus, NULL882, nullarmo, nyeogmi, Nylux, Nyranu, och-och, OCOtheOmega, OctoRocket, OldDanceJacket, osjarw, Ostaf, othymer, OttoMaticode, Owai-Seek, paigemaeforrest, pali6, Pangogie, panzer-iv1, paolordls, partyaddict, patrikturi, PaulRitter, Peptide90, peptron1, PeterFuto, PetMudstone, pewter-wiz, Phantom-Lily, PHCodes, Phill101, phunnyguy, pigeonpeas, PilgrimViis, Pill-U, Piras314, Pireax, pissdemon, PixelTheKermit, PJB3005, Plasmaguy, PlasmaRaptor, plinyvic, Plykiya, plyushsune, pofitlo, pointer-to-null, poklj, PolterTzi, PoorMansDreams, potato1234x, PotentiallyTom, ProfanedBane, PROG-MohamedDwidar, ProPandaBear, PrPleGoo, ps3moira, Pspritechologist, Psychpsyo, psykzz, PuceTint, PuroSlavKing, PursuitInAshes, Putnam3145, qrtDaniil, quatre, QuietlyWhisper, qwerltaz, Radezolid, RadioMull, Radosvik, Radrark, RadsammyT, Rainbeon, Rainfey, Raitononai, randy10122, Rane, Ranger6012, Rapidgame7, ravage123321, rbertoche, Redfire1331, RedFoxIV, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, Remuchi, rene-descartes2021, Renlou, retequizzle, rich-dunne, RieBi, riggleprime, RIKELOLDABOSS, Rinkashikachi, RobbyTheFish, Rockdtben, Rohesie, rok-povsic, rolfero, RomanNovo, rosieposieeee, Rosycup, router, RumiTiger, S1ss3l, Saakra, saga3152, Salex08, sam, Samsterious, SaphireLattice, SapphicOverload, sapphirescript, sarahon, SaveliyM360, sBasalto, ScalyChimp, ScarKy0, scrato, Scribbles0, scuffedjays, ScumbagDog, Segonist, sephtasm, Serkket, sewerpig, ShadowCommander, shadowtheprotogen546, shadowwailker, shaeone, shampunj, shariathotpatrol, ShatteredSwords, SignalWalker, siigiil, SimpleStation14, Simyon264, sirdragooon, Sirionaut, SixplyDev, Sk1tch, SkaldetSkaeg, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, SleepyScarecrow, sleepyyapril, Slyfox333, snebl, sniperchance, Snowni, snowsignal, SonicHDC, Sornarok, SoulFN, SoulSloth, Soundwavesghost, southbridge-fur, sowelipililimute, SpaceManiac, SpaceRox1244, SpaceyLady, spartak, SpartanKadence, Spatison, SpeltIncorrectyl, spess-empyrean, SphiraI, SplinterGP, spoogemonster, sporekto, Squishy77, ssdaniel24, stalengd, stanberytrask, Stanislav4ix, StanTheCarpenter, Stealthbomber16, stellar-novas, Stop-Signs, stopbreaking, stopka-html, StrawberryMoses, Stray-Pyramid, Strol20, StStevens, Subversionary, sunbear-dev, superjj18, Supernorn, suraru, SweptWasTaken, SX-7, Sybil, SYNCHRONIC, Szunti, TadJohnson00, takemysoult, TaralGit, Taran, Tayrtahn, tday93, TekuNut, telyonok, TemporalOroboros, tentekal, terezi4real, Terraspark4941, texcruize, TGRCdev, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, TheCze, TheDarkElites, thedraccx, TheEmber, TheIntoxicatedCat, thekilk, themias, theomund, TherapyGoth, TheShuEd, thevinter, ThunderBear2006, Timemaster99, Timfa2112, timothyteakettle, TimrodDX, tin-man-tim, Tirochora, Titian3, tk-a369, tkdrg, Tmanzxd, tmtmtl30, toasterpm87, Toby222, TokenStyle, Tollhouse, tom-leys, tomasalves8, Tomeno, Tonydatguy, topy, tornado-technology, Tornado-Technology, tosatur, TotallyLemon, trashalice, truepaintgit, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, twoducksonnaplane, Tyler-IN, Tyzemol, UbaserB, ubis1, UBlueberry, UKNOWH, UltimateJester, Unbelievable-Salmon, underscorex5, UnicornOnLSD, Unkn0wnGh0st333, unusualcrow, Uriende, UristMcDorf, user424242420, v0idRift, Vaaankas, valentfingerov, Varen, VasilisThePikachu, veliebm, VelonacepsCalyxEggs, veprolet, VerinSenpai, Veritius, Vermidia, vero5123, Verslebas, VigersRay, violet754, Visne, vlados1408, VMSolidus, volotomite, volundr-, Voomra, Vordenburg, vulppine, wafehling, Warentan, WarMechanic, Watermelon914, waylon531, weaversam8, wertanchik, whateverusername0, Willhelm53, WilliamECrew, willicassi, Winkarst-cpu, wirdal, wixoaGit, WlarusFromDaSpace, wrexbe, WTCWR68, xkreksx, xqzpop7, xRiriq, YanehCheck, yathxyz, Ygg01, YotaXP, youarereadingthis, Yousifb26, yunii, YuriyKiss, yuriykiss, zach-hill, Zadeon, zamp, Zandario, Zap527, Zealith-Gamer, zelezniciar1, ZelteHonor, zero, ZeroDiamond, zerorulez, ZeWaka, zionnBE, ZNixian, ZoldorfTheWizard, Zymem, zzylex +0x6273, 13spacemen, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 2digitman, 4310v343k, 4dplanner, 612git, 778b, Ablankmann, abregado, Absolute-Potato, Acruid, actually-reb, ada-please, adamsong, Adeinitas, Admiral-Obvious-001, adrian, Adrian16199, Aerocrux, Aexolott, Aexxie, africalimedrop, afrokada, Agoichi, Ahion, Aidenkrz, Aikakakah, aitorlogedo, ajcm, AJCM-git, AjexRose, Alekshhh, alexkar598, AlexMorgan3817, alexumandxgabriel08x, Alithsko, alliephante, ALMv1, AlphaQwerty, Altoids1, amylizzle, ancientpower, Andre19926, AndrewEyeke, angelofallars, Anzarot121, Appiah, ar4ill, ArchPigeon, ArchRBX, areitpog, Arendian, arimah, Arkanic, armoks, Arteben, ArthurMousatov, ArtisticRoomba, artur, AruMoon, as334, AsikKEsel, asperger-sind, aspiringlich, aspiringLich, astriloqua, avalon, avghdev, AzzyIsNotHere, BananaFlambe, BasedPugilist, BasedUser, beck-thompson, benev0, BGare, bhespiritu, bingojohnson, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, blitzthesquishy, bloodrizer, Bloody2372, blueDev2, BlueHNT, Boaz1111, BobdaBiscuit, BobTheSleder, boiled-water-tsar, BombasterDS, boogiebogus, botanySupremist, brainfood1183, BramvanZijp, Brandon-Huu, Bribrooo, Bright0, brndd, bryce0110, BubblegumBlue, buletsponge, byondfuckery, c0rigin, c4llv07e, CaasGit, capnsockless, CaptainSqrBeard, Carbonhell, Carolyn3114, Carou02, carteblanche4me, CatTheSystem, Centronias, CerberusWolfie, chairbender, Charlese2, chavonadelal, Cheackraze, cheesePizza2, Chief-Engineer, christhirtle, chromiumboy, Chronophylos, Chubbygummibear, CilliePaint, civilCornball, Clement-O, clyf, Clyybber, CMDR-Piboy314, CodedCrow, Cohnway, cojoke-dot, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, CormosLemming, CrafterKolyan, crazybrain23, creadth, CrigCrag, croilbird, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, DadeKuma, Daemon, daerSeebaer, dahnte, dakamakat, DamianX, dan, DangerRevolution, daniel-cr, DanSAussieITS, Daracke, DarkenedSynergy, Darkenson, DawBla, Daxxi3, dch-GH, Deahaka, dean, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, Deeeeja, deepdarkdepths, degradka, Delete69, deltanedas, DeltaV-Bot, DerbyX, derek, dersheppard, dexlerxd, dffdff2423, dge21, Diggy0, digitalic, DinoWattz, DisposableCrewmember42, DJB1gYAPPA, DjfjdfofdjfjD, DocNITE, DoctorBeard, DogZeroX, dolgovmi, dontbetank, Doomsdrayk, dootythefrooty, Dorragon, Doru991, DoubleRiceEddiedd, DoutorWhite, drakewill-CRL, Drayff, dribblydrone, DrMelon, drongood12, DrSingh, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, dukevanity, Dutch-VanDerLinde, dvir001, dylanstrategie, Dynexust, Easypoller, eclips_e, EctoplasmIsGood, eden077, EEASAS, Efruit, efzapa, ElectroSR, elsie, elthundercloud, Emisse, emmafornash, EmoGarbage404, Endecc, eoineoineoin, Erisfiregamer1, ERORR404V1, Errant-4, esguard, estacaoespacialpirata, eugene, Evgencheg, ewokswagger, exincore, exp111, f0x-n3rd, FacePluslll, Fahasor, FairlySadPanda, Fansana, Feluk6174, fenndragon, ficcialfaint, Fiftyllama, Fildrance, FillerVK, FinnishPaladin, FirinMaLazors, Fishfish458, fl-oz, Flareguy, FluffiestFloof, FluffMe, FluidRock, flybik, flyingkarii, FoLoKe, fooberticus, ForestNoises, forgotmyotheraccount, forkeyboards, forthbridge, Fortune117, Fouin, foxhorn, FoxxoTrystan, freeman2651, freeze2222, Froffy025, Fromoriss, froozigiusz, FrostMando, FryOfDestiny, FungiFellow, GalacticChimp, gamer3107, Gaxeer, gbasood, gcoremans, Geekyhobo, genderGeometries, GeneralGaws, Genkail, geraeumig, Ghagliiarghii, ghost581x, Git-Nivrak, gituhabu, GlassEclipse, gluesniffler, GNF54, GNUtopia, Golinth, GoodWheatley, gradientvera, graevy, GraniteSidewalk, GreaseMonk, greenrock64, greggthefather, GreyMario, GTRsound, Guess-My-Name, gusxyz, h3half, Haltell, Hanzdegloker, Hardly3D, harikattar, Hebi, Henry, HerCoyote23, hiucko, Hmeister-fake, Hmeister-real, hobnob, HoidC, Holinka4ever, holyssss, HoofedEar, Hoolny, hord-brayden, hubismal, Hugal31, Huxellberger, Hyenh, i-justuser-i, iacore, IamVelcroboy, icekot8, icesickleone, Ichaie, iczero, iglov, igorsaux, ike709, illersaver, Illiux, Ilushkins33, Ilya246, IlyaElDunaev, indeano, Injazz, Insineer, IntegerTempest, Interrobang01, Intoxicating-Innocence, IProduceWidgets, ItsMeThom, Itzbenz, Jackal298, Jackrost, jacksonzck, Jackw2As, jamessimo, janekvap, Jark255, Jaskanbe, JasperJRoth, jerryimmouse, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JimGamemaster, jimmy12or, JIPDawg, jjtParadox, JohnGinnane, johnku1, joshepvodka, Jrpl, jukereise, juliangiebel, juniwoofs, justart1m, JustCone14, justin, justintether, JustinTrotter, justtne, K-Dynamic, k3yw, Kadeo64, KaiShibaa, kalane15, kalanosh, Kanashi-Panda, Keelin, Keer-Sar, KEEYNy, keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, Kimpes, KingFroozy, kira-er, Kirillcas, Kistras, Kit0vras, KittenColony, klaypexx, Kmc2000, Ko4ergaPunk, kognise, komunre, KonstantinAngelov, koteq, Kr8art, Krunklehorn, Kukutis96513, Kupie, kxvvv, Kyoth25f, kzhanik, lajolico, Lamrr, LankLTE, laok233, lapatison, larryrussian, larynevespr, lawdog4817, Lazzi0706, leander-0, leonardo-dabepis, leonsfriedrich, LetterN, lettern, Level10Cybermancer, LEVELcat, lever1209, Lgibb18, LightVillet, liltenhead, LinkUyx, LittleBuilderJane, lizelive, lleftTheDragon, localcc, Lomcastar, lonoferars, LordCarve, LordEclipse, LovelyLophi, luckyshotpictures, LudwigVonChesterfield, Lukasz825700516, Lumminal, lunarcomets, luringens, lvvova1, Lyndomen, lzimann, lzk228, M3739, mac6na6na, MACMAN2003, Macoron, magicalus, magmodius, MagnusCrowe, malchanceux, MaloTV, ManelNavola, Mangohydra, marboww, Markek1, Matz05, max, MaxNox7, MehimoNemo, MeltedPixel, MemeProof, MendaxxDev, Menshin, Mephisto72, Mervill, metalgearsloth, mhamsterr, michaelcu, micheel665, Mike32oz, MilenVolf, milon, MilonPL, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, MjrLandWhale, MLGTASTICa, Mnemotechnician, moderatelyaware, mokiros, Moneyl, Monotheonist, Moomoobeef, moony, Morb0, mr-bo-jangles, Mr0maks, MrFippik, musicmanvr, MWKane, Myakot, Myctai, N3X15, nails-n-tape, Nairodian, Naive817, namespace-Memory, Nannek, NeLepus, neuPanda, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, NIXC, NkoKirkto, nmajask, noctyrnal, nok-ko, NonchalantNoob, NoobyLegion, not-gavnaed, notafet, notquitehadouken, noudoit, noverd, NuclearWinter, nukashimika, nuke-haus, NULL882, nullarmo, nyeogmi, Nylux, Nyranu, och-och, OCOtheOmega, OctoRocket, OldDanceJacket, osjarw, Ostaf, othymer, OttoMaticode, Owai-Seek, paigemaeforrest, pali6, Pangogie, panzer-iv1, paolordls, partyaddict, patrikturi, PaulRitter, Peptide90, peptron1, PeterFuto, PetMudstone, pewter-wiz, Phantom-Lily, PHCodes, Phill101, phunnyguy, pigeonpeas, PilgrimViis, Pill-U, Piras314, Pireax, pissdemon, PixelTheKermit, PJB3005, Plasmaguy, PlasmaRaptor, plinyvic, Plykiya, plyushsune, pofitlo, pointer-to-null, poklj, PolterTzi, PoorMansDreams, potato1234x, PotentiallyTom, ProfanedBane, PROG-MohamedDwidar, ProPandaBear, PrPleGoo, ps3moira, Pspritechologist, Psychpsyo, psykzz, PuceTint, PuroSlavKing, PursuitInAshes, Putnam3145, qrtDaniil, quatre, QuietlyWhisper, qwerltaz, Radezolid, RadioMull, Radosvik, Radrark, RadsammyT, Raikyr0, Rainbeon, Rainfey, Raitononai, randy10122, Rane, Ranger6012, Rapidgame7, ravage123321, rbertoche, Redfire1331, RedFoxIV, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, Remuchi, rene-descartes2021, Renlou, retequizzle, rich-dunne, RieBi, riggleprime, RIKELOLDABOSS, Rinkashikachi, RobbyTheFish, Rockdtben, Rohesie, rok-povsic, rolfero, RomanNovo, rosieposieeee, Rosycup, router, RumiTiger, S1ss3l, Saakra, saga3152, Salex08, sam, Samsterious, SaphireLattice, SapphicOverload, sapphirescript, sarahon, SaveliyM360, sBasalto, ScalyChimp, ScarKy0, scrato, Scribbles0, scuffedjays, ScumbagDog, Segonist, sephtasm, Serkket, sewerpig, ShadowCommander, shadowtheprotogen546, shadowwailker, shaeone, shampunj, shariathotpatrol, ShatteredSwords, SignalWalker, siigiil, SimpleStation14, Simyon264, sirdragooon, Sirionaut, SixplyDev, Sk1tch, SkaldetSkaeg, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, SleepyScarecrow, sleepyyapril, Slyfox333, snebl, sniperchance, Snowni, snowsignal, SonicHDC, Sornarok, SoulFN, SoulSloth, Soundwavesghost, southbridge-fur, sowelipililimute, SpaceManiac, SpaceRox1244, SpaceyLady, spartak, SpartanKadence, Spatison, SpeltIncorrectyl, spess-empyrean, SphiraI, SplinterGP, spoogemonster, sporekto, Squishy77, ssdaniel24, stalengd, stanberytrask, Stanislav4ix, StanTheCarpenter, Stealthbomber16, stellar-novas, Stop-Signs, stopbreaking, stopka-html, StrawberryMoses, Stray-Pyramid, Strol20, StStevens, Subversionary, sunbear-dev, superjj18, Supernorn, suraru, SweptWasTaken, SX-7, Sybil, SYNCHRONIC, Szunti, TadJohnson00, takemysoult, TaralGit, Taran, Tayrtahn, tday93, TekuNut, telyonok, TemporalOroboros, tentekal, terezi4real, Terraspark4941, texcruize, TGRCdev, tgrkzus, thatrandomcanadianguy, TheArturZh, TheCze, TheDarkElites, thedraccx, TheEmber, TheIntoxicatedCat, thekilk, themias, theomund, TherapyGoth, TheShuEd, thevinter, ThunderBear2006, Timemaster99, Timfa2112, timothyteakettle, TimrodDX, tin-man-tim, Tirochora, Titian3, tk-a369, tkdrg, Tmanzxd, tmtmtl30, toasterpm87, Toby222, TokenStyle, Tollhouse, tom-leys, tomasalves8, Tomeno, Tonk-GCR, Tonydatguy, topy, Tornado-Technology, tornado-technology, tosatur, TotallyLemon, trashalice, truepaintgit, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, twoducksonnaplane, Tyler-IN, Tyzemol, UbaserB, ubis1, UBlueberry, UKNOWH, UltimateJester, Unbelievable-Salmon, underscorex5, UnicornOnLSD, Unkn0wnGh0st333, unusualcrow, Uriende, UristMcDorf, user424242420, v0idRift, Vaaankas, valentfingerov, Varen, VasilisThePikachu, veliebm, VelonacepsCalyxEggs, veprolet, VerinSenpai, Veritius, Vermidia, vero5123, Verslebas, VigersRay, violet754, Visne, vlados1408, VMSolidus, volotomite, volundr-, Voomra, Vordenburg, vulppine, wafehling, Warentan, WarMechanic, Watermelon914, waylon531, weaversam8, wertanchik, whateverusername0, Willhelm53, WilliamECrew, willicassi, Winkarst-cpu, wirdal, wixoaGit, WlarusFromDaSpace, wrexbe, WTCWR68, xkreksx, xqzpop7, xRiriq, YanehCheck, yathxyz, Ygg01, YotaXP, youarereadingthis, Yousifb26, yunii, yuriykiss, YuriyKiss, zach-hill, Zadeon, zamp, Zandario, Zap527, Zealith-Gamer, zelezniciar1, ZelteHonor, zero, ZeroDiamond, zerorulez, ZeWaka, zionnBE, ZNixian, ZoldorfTheWizard, Zymem, zzylex diff --git a/Resources/Locale/en-US/_Goobstation/martial-arts/martial-arts.ftl b/Resources/Locale/en-US/_Goobstation/martial-arts/martial-arts.ftl new file mode 100644 index 0000000000..d898cf23ff --- /dev/null +++ b/Resources/Locale/en-US/_Goobstation/martial-arts/martial-arts.ftl @@ -0,0 +1,44 @@ +cqc-fail-used = {CAPITALIZE(THE($manual))} is already used. +cqc-fail-notself = You can't teach anyone with {CAPITALIZE(THE($manual))}. + +cqc-fail-knowanother = You already know another martial art. +cqc-fail-already = You already know everything about a Martial art. +cqc-success-unblocked = Your CQC skills are not bound to kitchen anymore. +cqc-success-learned = You have learned CQC. + +cqc-manual-used = [color=white]{CAPITALIZE(THE($manual))} looks to be already used.[/color] + +ent-CQCManual = CQC manual + .desc = Looks like a usual book, but contains some secrets inside. + +carp-scroll-waiting = The journey of a thousand miles begins with one step, and the path of wisdom is traveled slowly, one lesson at a time. +carp-scroll-advance = You have taken one step closer to becoming a master of the Way of the Sleeping Carp. +carp-scroll-complete = You are now a master of the Way of the Sleeping Carp. + +carp-saying-huah = HUAH! +carv-saying-hya = HYA! +carp-saying-choo = CHOO! +carp-saying-wuo = WUO! +carp-saying-kya = KYA! +carp-saying-huh = HUH! +carp-saying-hiyoh = HIYOH! +carp-saying-strike = CARP STRIKE! +carp-saying-bite = CARP BITE! + +carp-saying-banzai = BANZAIII! +carp-saying-kiya = KIYAAAA! +carp-saying-omae = OMAE WA MOU SHINDEIRU! +carp-saying-see = YOU CAN'T SEE ME! +carp-saying-time = MY TIME IS NOW!! +carp-saying-cowabunga = COWABUNGA! + +krav-maga-ready = You ready a {$action} + +martial-arts-action-sender = You hit {$name} with {$move} +martial-arts-action-receiver = {$name} hit you with {$move} + +uplink-cqc-name = CQC Manual +uplink-cqc-desc = A manual that teaches a single user tactical Close-Quarters Combat before self-destructing. Does not restrict weapon usage. Your disarms will inflict some stamina damage while making people temporarily slur their words, your grabs will immobilize for a second making it easier to reinforce them, your harm attacks will deal moderate stamina damage, and you will get a set of combos that allow you to efficiently knockdown, disarm or stun your opponent. You can find more information on CQC and its combos here. + +uplink-sleeping-carp-name = Martial Arts Scroll +uplink-sleeping-carp-desc = This scroll contains the secrets of an ancient martial arts technique. You will master unarmed combat, deflecting ranged weapon fire. Learning this art means you will also refuse to use dishonorable ranged weaponry. Unable to be understood by vampire and changeling agents. diff --git a/Resources/Locale/en-US/_white/objectives/conditions/steal.ftl b/Resources/Locale/en-US/_white/objectives/conditions/steal.ftl deleted file mode 100644 index 5f3bb96986..0000000000 --- a/Resources/Locale/en-US/_white/objectives/conditions/steal.ftl +++ /dev/null @@ -1 +0,0 @@ -steal-target-power-gloves = power gloves diff --git a/Resources/Locale/en-US/extenddescriptions/items/revolutionarymanifesto.ftl b/Resources/Locale/en-US/extenddescriptions/items/revolutionarymanifesto.ftl new file mode 100644 index 0000000000..4d3182f725 --- /dev/null +++ b/Resources/Locale/en-US/extenddescriptions/items/revolutionarymanifesto.ftl @@ -0,0 +1,4 @@ +revolutionarymanifesto-extenddescription-headrevolutionary = I can use this item to convert others to my cause. +revolutionarymanifesto-extenddescription-revolutionary = My revolutionary leader can use this item to convert others to our cause. +revolutionarymanifesto-extenddescription-security = Despite its dangerous ideology, this book is not illegal to possess. +revolutionarymanifesto-extenddescription-mindshield = An affront to all values a righteous Nanotrasen employee should stand for! diff --git a/Resources/Locale/en-US/extenddescriptions/items/weapons/civiliandisabler.ftl b/Resources/Locale/en-US/extenddescriptions/items/weapons/civiliandisabler.ftl new file mode 100644 index 0000000000..95f0e08620 --- /dev/null +++ b/Resources/Locale/en-US/extenddescriptions/items/weapons/civiliandisabler.ftl @@ -0,0 +1 @@ +civiliandisabler-extenddescription-security = This weapon is legal to own and carry without a license on NanoTrasen stations, but may be considered as an accessory equivalent to a weapon if used in a crime. diff --git a/Resources/Locale/ru-RU/_white/object/clothes/gloves.ftl b/Resources/Locale/ru-RU/_white/object/clothes/gloves.ftl deleted file mode 100644 index 22fa1077a9..0000000000 --- a/Resources/Locale/ru-RU/_white/object/clothes/gloves.ftl +++ /dev/null @@ -1,3 +0,0 @@ -ent-ClothingHandsGlovesPowergloveReal = силовые перчатки - .desc = Помни основы CQC. - .suffix = { "Смотритель" } diff --git a/Resources/Locale/ru-RU/_white/objectives/conditions/steal.ftl b/Resources/Locale/ru-RU/_white/objectives/conditions/steal.ftl deleted file mode 100644 index 9414d7035b..0000000000 --- a/Resources/Locale/ru-RU/_white/objectives/conditions/steal.ftl +++ /dev/null @@ -1 +0,0 @@ -steal-target-power-gloves = силовые перчатки diff --git a/Resources/Locale/ru-RU/loadouts/jobs/security.ftl b/Resources/Locale/ru-RU/loadouts/jobs/security.ftl index fe3e4bfc7e..8dced373c8 100644 --- a/Resources/Locale/ru-RU/loadouts/jobs/security.ftl +++ b/Resources/Locale/ru-RU/loadouts/jobs/security.ftl @@ -1,7 +1,6 @@ loadout-description-LoadoutSecurityUniformJumpskirtSenior = A skirt fit for the best of the best. loadout-description-LoadoutSecurityUniformJumpsuitSenior = A suit fit for the best of the best. loadout-description-LoadoutSecurityShoesJackboots = A really nice, heavy, pair of black boots. - # Equipment loadout-name-LoadoutMagazinePistolSpare = pistol magazine (.35 auto, spare) loadout-name-LoadoutSpeedLoaderMagnumSpare = speed loader (.45 magnum, spare) diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/security.yml b/Resources/Prototypes/Catalog/Fills/Lockers/security.yml index 5b5e1dde4b..5f2c2e95c2 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/security.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/security.yml @@ -5,31 +5,31 @@ components: - type: StorageFill contents: - - id: ClothingHandsGlovesPowergloveReal # WWDP, traitor steal objective, to do replace with krav-magas - - id: FlashlightSeclite - - id: WeaponDisabler - prob: 0.3 - - id: ClothingBeltSecurityFilled - - id: Flash - - id: ClothingEyesGlassesSunglasses - - id: ClothingHeadsetAltSecurity - # - id: ClothingHandsGlovesCombat # WWDP, replaced by powergloves - - id: ClothingShoesBootsJack - - id: ClothingOuterCoatWarden - - id: ClothingOuterWinterWarden - - id: RubberStampWarden - - id: DoorRemoteArmory - - id: ClothingOuterHardsuitWarden # WWDP edit - - id: OxygenTankFilled # WWDP edit - - id: HoloprojectorSecurity - - id: ClothingEyesHudSecurity - - id: BoxPDAPrisoner # Delta-V - - id: ClothingShoesBootsWinterWarden #Delta V: Add departmental winter boots - - id: BoxEncryptionKeyPrisoner #Delta-V - - id: BoxPrisonerHeadset - - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! - prob: 0.3 - - id: BoxBodyBagPrisoner # WD + - id: FlashlightSeclite + - id: WeaponDisabler + prob: 0.3 + - id: ClothingBeltSecurityFilled + - id: ClothingHandsGlovesKravMaga # Goobstation - Martial Arts + - id: Flash + - id: ClothingEyesGlassesSunglasses + - id: ClothingHeadsetAltSecurity + - id: ClothingHandsGlovesCombat + - id: ClothingShoesBootsJack + - id: ClothingOuterCoatWarden + - id: ClothingOuterWinterWarden + - id: RubberStampWarden + - id: DoorRemoteArmory + - id: ClothingOuterHardsuitWarden # WWDP edit + - id: OxygenTankFilled # WWDP edit + - id: HoloprojectorSecurity + - id: ClothingEyesHudSecurity + - id: BoxPDAPrisoner # Delta-V + - id: ClothingShoesBootsWinterWarden #Delta V: Add departmental winter boots + - id: BoxEncryptionKeyPrisoner #Delta-V + - id: BoxPrisonerHeadset + - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! + prob: 0.3 + - id: BoxBodyBagPrisoner # WD - type: entity id: LockerWardenFilled @@ -38,29 +38,29 @@ components: - type: StorageFill contents: - - id: ClothingHandsGlovesPowergloveReal # WWDP, traitor steal objective, to do replace with krav-magas - - id: FlashlightSeclite - - id: WeaponDisabler - prob: 0.3 - - id: ClothingBeltSecurityFilled - - id: Flash - - id: ClothingEyesGlassesSunglasses - - id: ClothingHeadsetAltSecurity - # - id: ClothingHandsGlovesCombat # WWDP, replaced by powergloves - - id: ClothingShoesBootsJack - - id: ClothingOuterCoatWarden - - id: ClothingOuterWinterWarden - - id: RubberStampWarden - - id: DoorRemoteArmory - - id: HoloprojectorSecurity - - id: ClothingEyesHudSecurity - - id: BoxPDAPrisoner # Delta-V - - id: ClothingShoesBootsWinterWarden #Delta V: Add departmental winter boots - - id: BoxEncryptionKeyPrisoner #Delta-V - - id: BoxPrisonerHeadset - - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! - prob: 0.3 - - id: BoxBodyBagPrisoner # WD + - id: FlashlightSeclite + - id: WeaponDisabler + prob: 0.3 + - id: ClothingBeltSecurityFilled + - id: ClothingHandsGlovesKravMaga # Goobstation - Martial Arts + - id: Flash + - id: ClothingEyesGlassesSunglasses + - id: ClothingHeadsetAltSecurity + - id: ClothingHandsGlovesCombat + - id: ClothingShoesBootsJack + - id: ClothingOuterCoatWarden + - id: ClothingOuterWinterWarden + - id: RubberStampWarden + - id: DoorRemoteArmory + - id: HoloprojectorSecurity + - id: ClothingEyesHudSecurity + - id: BoxPDAPrisoner # Delta-V + - id: ClothingShoesBootsWinterWarden #Delta V: Add departmental winter boots + - id: BoxEncryptionKeyPrisoner #Delta-V + - id: BoxPrisonerHeadset + - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! + prob: 0.3 + - id: BoxBodyBagPrisoner # WD - type: entity id: LockerSecurityFilled @@ -69,21 +69,24 @@ components: - type: StorageFill contents: - - id: FlashlightSeclite - - id: ClothingUniformJumpsuitSec # WD - Less random bloat - - id: ClothingHeadHelmetBasic - # - id: ClothingHeadHelmetInsulated # Nyanotrasen - Insulative headgear # WWDP - all sec helmets are insulated now - - id: ClothingOuterArmorBasic # WD - plate carrier and stabproof vest replaced back to regular bodyarmor - - id: ClothingBeltSecurityFilled - - id: ClothingEyesGlassesSecurity # WD - SecHuds - - id: ClothingHeadsetSecurity - - id: ClothingHandsGlovesColorBlack - - id: ClothingShoesBootsJack - - id: WeaponDisabler # WD - - id: WeaponMeleeNeedle - prob: 0.1 - - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! - prob: 0.3 + - id: FlashlightSeclite + - id: ClothingUniformJumpsuitSec # WD - Less random bloat + - id: ClothingHeadHelmetBasic + # - id: ClothingHeadHelmetInsulated # Nyanotrasen - Insulative headgear # WWDP - all sec helmets are insulated now + - id: ClothingOuterArmorBasic # WD - plate carrier and stabproof vest replaced back to regular bodyarmor + - id: ClothingBeltSecurityFilled + - id: ClothingBeltCorporateJudo # Goobstation - Martial Arts + - id: Flash + prob: 0.5 + - id: ClothingEyesGlassesSecurity # WD - SecHuds + - id: ClothingHeadsetSecurity + - id: ClothingHandsGlovesColorBlack + - id: ClothingShoesBootsJack + - id: WeaponDisabler # WD + - id: WeaponMeleeNeedle + prob: 0.1 + - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! + prob: 0.3 - type: entity id: LockerBrigmedicFilled @@ -92,37 +95,37 @@ components: - type: StorageFill contents: - - id: ClothingEyesGlassesCorpsman # DeltaV - Corpsman Glasses - - id: WeaponDisabler - - id: TrackingImplanter - amount: 2 -## - id: ClothingOuterHardsuitCombatCorpsman # DeltaV - ClothingOuterHardsuitBrigmedic replaced in favour of corpsman's combat hardsuit; removing from standard filled locker to place in hardsuit filled locker. - - id: BoxSterileMask - - id: ClothingHeadHatBeretCorpsman # DeltaV - ClothingHeadHatBeretBrigmedic replaced in favour of corpsman beret. -## - id: ClothingOuterCoatAMG # DeltaV - removed until I can resprite it or replace it. - - id: ClothingUniformJumpsuitBrigmedic - - id: ClothingUniformJumpskirtBrigmedic -## - id: ClothingUniformJumpskirtOfLife # DeltaV - nah -## prob: 0.1 - - id: HandheldGPSBasic # Delta V - added it for tracking the implant tracker pop up. - - id: MedkitFilled - - id: MedkitCombatFilled - prob: 0.6 - - id: MedkitAdvancedFilled - prob: 0.4 - - id: MedkitOxygenFilled - prob: 0.3 - - id: MedkitBruteFilled - prob: 0.3 - - id: MedkitToxinFilled - prob: 0.3 - - id: MedkitBurnFilled - prob: 0.7 -## - id: ClothingNeckCloakMoth #bzzz Moth-pocalypse # DeltaV - why -## prob: 0.15 - - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! - prob: 0.3 - - id: BoxBodyBagPrisoner # WD + - id: ClothingEyesGlassesCorpsman # DeltaV - Corpsman Glasses + - id: WeaponDisabler + - id: TrackingImplanter + amount: 2 + ## - id: ClothingOuterHardsuitCombatCorpsman # DeltaV - ClothingOuterHardsuitBrigmedic replaced in favour of corpsman's combat hardsuit; removing from standard filled locker to place in hardsuit filled locker. + - id: BoxSterileMask + - id: ClothingHeadHatBeretCorpsman # DeltaV - ClothingHeadHatBeretBrigmedic replaced in favour of corpsman beret. + ## - id: ClothingOuterCoatAMG # DeltaV - removed until I can resprite it or replace it. + - id: ClothingUniformJumpsuitBrigmedic + - id: ClothingUniformJumpskirtBrigmedic + ## - id: ClothingUniformJumpskirtOfLife # DeltaV - nah + ## prob: 0.1 + - id: HandheldGPSBasic # Delta V - added it for tracking the implant tracker pop up. + - id: MedkitFilled + - id: MedkitCombatFilled + prob: 0.6 + - id: MedkitAdvancedFilled + prob: 0.4 + - id: MedkitOxygenFilled + prob: 0.3 + - id: MedkitBruteFilled + prob: 0.3 + - id: MedkitToxinFilled + prob: 0.3 + - id: MedkitBurnFilled + prob: 0.7 + ## - id: ClothingNeckCloakMoth #bzzz Moth-pocalypse # DeltaV - why + ## prob: 0.15 + - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! + prob: 0.3 + - id: BoxBodyBagPrisoner # WD # DeltaV - adding corpsman locker w/ hardsuit @@ -133,31 +136,31 @@ components: - type: StorageFill contents: - - id: ClothingEyesGlassesCorpsman # DeltaV - Corpsman Glasses - - id: WeaponDisabler - - id: TrackingImplanter - amount: 2 - - id: ClothingOuterHardsuitBrigmedic # WWDP edit - - id: OxygenTankFilled # WWDP edit - - id: ClothingUniformJumpsuitBrigmedic - - id: ClothingUniformJumpskirtBrigmedic - - id: HandheldGPSBasic # Added GPS because I just think it should be there tbh. - - id: MedkitFilled - - id: MedkitCombatFilled - prob: 0.6 - - id: MedkitAdvancedFilled - prob: 0.4 - - id: MedkitOxygenFilled - prob: 0.3 - - id: MedkitBruteFilled - prob: 0.3 - - id: MedkitToxinFilled - prob: 0.3 - - id: MedkitBurnFilled - prob: 0.7 - - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! - prob: 0.3 - - id: BoxBodyBagPrisoner # WD + - id: ClothingEyesGlassesCorpsman # DeltaV - Corpsman Glasses + - id: WeaponDisabler + - id: TrackingImplanter + amount: 2 + - id: ClothingOuterHardsuitBrigmedic # WWDP edit + - id: OxygenTankFilled # WWDP edit + - id: ClothingUniformJumpsuitBrigmedic + - id: ClothingUniformJumpskirtBrigmedic + - id: HandheldGPSBasic # Added GPS because I just think it should be there tbh. + - id: MedkitFilled + - id: MedkitCombatFilled + prob: 0.6 + - id: MedkitAdvancedFilled + prob: 0.4 + - id: MedkitOxygenFilled + prob: 0.3 + - id: MedkitBruteFilled + prob: 0.3 + - id: MedkitToxinFilled + prob: 0.3 + - id: MedkitBurnFilled + prob: 0.7 + - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! + prob: 0.3 + - id: BoxBodyBagPrisoner # WD # DeltaV - end addition @@ -168,23 +171,23 @@ components: - type: StorageFill contents: - - id: ClothingEyesHudSecurity - prob: 0.3 - - id: ClothingHeadHatFedoraBrown - - id: ClothingNeckTieDet - - id: ClothingOuterVestDetective - - id: ClothingOuterCoatDetective - - id: FlashlightSeclite - - id: ForensicScanner - - id: LogProbeCartridge - - id: BoxForensicPad - - id: DrinkDetFlask - - id: ClothingHandsGlovesForensic - - id: RubberStampDetective - - id: HoloprojectorSecurity - - id: BoxEvidenceMarkers - - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! - prob: 0.3 + - id: ClothingEyesHudSecurity + prob: 0.3 + - id: ClothingHeadHatFedoraBrown + - id: ClothingNeckTieDet + - id: ClothingOuterVestDetective + - id: ClothingOuterCoatDetective + - id: FlashlightSeclite + - id: ForensicScanner + - id: LogProbeCartridge + - id: BoxForensicPad + - id: DrinkDetFlask + - id: ClothingHandsGlovesForensic + - id: RubberStampDetective + - id: HoloprojectorSecurity + - id: BoxEvidenceMarkers + - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! + prob: 0.3 - type: entity id: ClosetBombFilled @@ -193,15 +196,15 @@ components: - type: StorageFill contents: - - id: ClothingHeadHelmetBombSuit - - id: ClothingOuterSuitBomb - # NT is cheap, what can you do... - - id: Wirecutter - prob: 0.9 - - id: Screwdriver - prob: 0.9 - - id: Multitool - prob: 0.5 + - id: ClothingHeadHelmetBombSuit + - id: ClothingOuterSuitBomb + # NT is cheap, what can you do... + - id: Wirecutter + prob: 0.9 + - id: Screwdriver + prob: 0.9 + - id: Multitool + prob: 0.5 - type: entity parent: GunSafe diff --git a/Resources/Prototypes/Entities/Objects/Specific/revolutionary.yml b/Resources/Prototypes/Entities/Objects/Specific/revolutionary.yml index 51b3d631fb..96f6505a2b 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/revolutionary.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/revolutionary.yml @@ -22,6 +22,38 @@ sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg - type: EmitSoundOnLand sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg + - type: ExtendDescription + descriptionList: + - description: "revolutionarymanifesto-extenddescription-headrevolutionary" + fontSize: 12 + color: "#880000" + requireDetailRange: false + requirements: + - !type:CharacterAntagonistRequirement + antagonists: + - HeadRev + - description: "revolutionarymanifesto-extenddescription-revolutionary" + fontSize: 12 + color: "#880000" + requireDetailRange: false + requirements: + - !type:CharacterAntagonistRequirement + antagonists: + - Rev + - description: "revolutionarymanifesto-extenddescription-security" + fontSize: 12 + color: "#ff0000" + requireDetailRange: true + requirements: + - !type:CharacterDepartmentRequirement + departments: + - Security + - description: "revolutionarymanifesto-extenddescription-mindshield" + fontSize: 12 + color: "#11aaff" + requireDetailRange: true + requirements: + - !type:CharacterMindshieldRequirement - type: GuideHelp guides: - Revolutionaries diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index c5d8c3d014..1e9bd4e429 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -603,6 +603,16 @@ steps: 5 zeroVisible: true - type: Appearance + - type: ExtendDescription + descriptionList: + - description: "civiliandisabler-extenddescription-security" + fontSize: 12 + color: "#ff0000" + requireDetailRange: true + requirements: + - !type:CharacterDepartmentRequirement + departments: + - Security - type: MeleeWeapon damage: types: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/security.yml b/Resources/Prototypes/Entities/Objects/Weapons/security.yml index e0aba41a4b..57dba8e676 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/security.yml @@ -13,7 +13,7 @@ tags: - Stunbaton - type: Stunbaton - energyPerUse: 50 # WD EDIT + energyPerUse: 50 - type: ItemToggle predictable: false soundActivate: @@ -64,7 +64,7 @@ - type: Appearance - type: GenericVisualizer visuals: - enum.ToggleVisuals.Toggled: + enum.ToggleVisuals.Toggled: enum.ToggleVisuals.Layer: True: {state: stunbaton_on} False: {state: stunbaton_off} @@ -90,6 +90,8 @@ - type: GuideHelp guides: - Security + - type: MartialArtBlocked # Goobstation - Martial Arts + form: CorporateJudo # Goobstation - Martial Arts - type: KnockdownOnHit # WD EDIT - type: entity @@ -139,67 +141,49 @@ id: Flash description: An ultrabright flashbulb with a trigger, which causes the victim to be dazed and lose their eyesight for a moment. Useless when burnt out. components: - - type: Sprite - sprite: Objects/Weapons/Melee/flash.rsi - layers: - - state: flash - map: [ "enum.FlashVisuals.BaseLayer" ] - - state: flashing - map: [ "enum.FlashVisuals.LightLayer" ] - visible: false - shader: unshaded - - type: Flash - - type: ExtendDescription - descriptionList: - - description: "flash-extenddescription-headrevolutionary" - fontSize: 12 - color: "#880000" - requireDetailRange: false - requirements: - - !type:CharacterAntagonistRequirement - antagonists: - - HeadRev - - description: "flash-extenddescription-revolutionary" - fontSize: 12 - color: "#880000" - requireDetailRange: false - requirements: - - !type:CharacterAntagonistRequirement - antagonists: - - Rev - - type: LimitedCharges - maxCharges: 5 - charges: 5 - - type: MeleeWeapon - canBeBlocked: false # WD EDIT - wideAnimationRotation: 180 - damage: - types: - Blunt: 0 # melee weapon to allow flashing individual targets - angle: 10 - - type: Item - size: Small - sprite: Objects/Weapons/Melee/flash.rsi -# - type: DynamicPrice -# price: 40 - - type: ReverseEngineering # Nyano - recipes: - - Flash - - type: StaticPrice - price: 40 - - type: Appearance - - type: GenericVisualizer - visuals: - enum.FlashVisuals.Burnt: - enum.FlashVisuals.BaseLayer: - True: {state: burnt} - enum.FlashVisuals.Flashing: - enum.FlashVisuals.LightLayer: - True: {visible: true} - False: {visible: false} - - type: GuideHelp - guides: - - Security + - type: Sprite + sprite: Objects/Weapons/Melee/flash.rsi + layers: + - state: flash + map: [ "enum.FlashVisuals.BaseLayer" ] + - state: flashing + map: [ "enum.FlashVisuals.LightLayer" ] + visible: false + shader: unshaded + - type: Flash + - type: LimitedCharges + maxCharges: 5 + charges: 5 + - type: MeleeWeapon + canBeBlocked: false # WD EDIT + wideAnimationRotation: 180 + damage: + types: + Blunt: 0 # melee weapon to allow flashing individual targets + angle: 10 + - type: Item + size: Small + sprite: Objects/Weapons/Melee/flash.rsi + # - type: DynamicPrice + # price: 40 + - type: ReverseEngineering # Nyano + recipes: + - Flash + - type: StaticPrice + price: 40 + - type: Appearance + - type: GenericVisualizer + visuals: + enum.FlashVisuals.Burnt: + enum.FlashVisuals.BaseLayer: + True: {state: burnt} + enum.FlashVisuals.Flashing: + enum.FlashVisuals.LightLayer: + True: {visible: true} + False: {visible: false} + - type: GuideHelp + guides: + - Security - type: entity name: flash @@ -207,9 +191,9 @@ suffix: 2 charges id: SciFlash components: - - type: LimitedCharges - maxCharges: 2 - charges: 2 + - type: LimitedCharges + maxCharges: 2 + charges: 2 - type: entity name: portable flasher @@ -217,44 +201,44 @@ id: PortableFlasher description: An ultrabright flashbulb with a proximity trigger, useful for making an area security-only. components: - - type: EmitSoundOnTrigger - sound: - path: /Audio/Weapons/flash.ogg - - type: FlashOnTrigger - range: 3 - - type: TriggerOnProximity - enabled: true - cooldown: 5 - shape: - !type:PhysShapeCircle - radius: 2 - repeating: true - - type: Anchorable - - type: Sprite - sprite: Objects/Weapons/pflash.rsi - layers: - - state: "off" - map: ["enum.ProximityTriggerVisualLayers.Base"] - - type: InteractionOutline - - type: Physics - - type: Fixtures - fixtures: - fix1: - shape: - !type:PhysShapeAabb - bounds: "-0.15,-0.3,0.15,0.3" - mask: - - MachineMask - layer: - - MachineLayer - density: 380 - - type: Appearance - - type: AnimationPlayer - - type: PointLight - energy: 2.0 - radius: 0 - softness: 0 - enabled: true - - type: GuideHelp - guides: - - Security + - type: EmitSoundOnTrigger + sound: + path: /Audio/Weapons/flash.ogg + - type: FlashOnTrigger + range: 3 + - type: TriggerOnProximity + enabled: true + cooldown: 5 + shape: + !type:PhysShapeCircle + radius: 2 + repeating: true + - type: Anchorable + - type: Sprite + sprite: Objects/Weapons/pflash.rsi + layers: + - state: "off" + map: ["enum.ProximityTriggerVisualLayers.Base"] + - type: InteractionOutline + - type: Physics + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.15,-0.3,0.15,0.3" + mask: + - MachineMask + layer: + - MachineLayer + density: 380 + - type: Appearance + - type: AnimationPlayer + - type: PointLight + energy: 2.0 + radius: 0 + softness: 0 + enabled: true + - type: GuideHelp + guides: + - Security diff --git a/Resources/Prototypes/Entities/Structures/Doors/airlock_groups.yml b/Resources/Prototypes/Entities/Structures/Doors/airlock_groups.yml index 9ca751b55d..cf9c04b818 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/airlock_groups.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/airlock_groups.yml @@ -14,7 +14,7 @@ security: Structures/Doors/Airlocks/Standard/security.rsi virology: Structures/Doors/Airlocks/Standard/virology.rsi justice: DeltaV/Structures/Doors/Airlocks/Standard/justice.rsi # Delta V - Add Justice Dept - roboticist: DeltaV/Structures/Doors/Airlocks/Glass/roboticist.rsi #Added Roboticist Role + roboticist: DeltaV/Structures/Doors/Airlocks/Standard/roboticist.rsi # Added Roboticist Role - type: AirlockGroup id: Glass diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml index 195070eb22..aadab6e424 100644 --- a/Resources/Prototypes/Objectives/objectiveGroups.yml +++ b/Resources/Prototypes/Objectives/objectiveGroups.yml @@ -12,7 +12,6 @@ weights: CaptainIDStealObjective: 1 CMOHyposprayStealObjective: 1 - PowerGlovesStealObjective: 1 # WWDP warden's CQC gloves CMOCrewMonitorStealObjective: 1 RDHardsuitStealObjective: 1 NukeDiskStealObjective: 1 diff --git a/Resources/Prototypes/Recipes/Lathes/sheet.yml b/Resources/Prototypes/Recipes/Lathes/sheet.yml index 7088b84cae..343ec1d01f 100644 --- a/Resources/Prototypes/Recipes/Lathes/sheet.yml +++ b/Resources/Prototypes/Recipes/Lathes/sheet.yml @@ -3,7 +3,7 @@ result: SheetSteel1 applyMaterialDiscount: false miningPoints: 1 - completetime: 0 + completetime: 0.0083 # 0.25 per 30 materials: RawIron: 100 Coal: 30 @@ -20,8 +20,8 @@ id: SheetGlass1 result: SheetGlass1 applyMaterialDiscount: false - miningPoints: 1 - completetime: 0 + miningPoints: 1 # 0.25 per 30 + completetime: 0.0083 materials: RawQuartz: 100 @@ -37,7 +37,7 @@ result: SheetRGlass1 applyMaterialDiscount: false miningPoints: 1 - completetime: 0 + completetime: 0.025 # 0.75 per 30 materials: Glass: 100 Steel: 50 @@ -55,7 +55,7 @@ - type: latheRecipe id: SheetPGlass1 result: SheetPGlass1 - completetime: 0 + completetime: 0.0083 # 0.75 per 30 miningPoints: 16 materials: RawQuartz: 100 @@ -72,7 +72,7 @@ - type: latheRecipe id: SheetRPGlass1 result: SheetRPGlass1 - completetime: 0 + completetime: 0.025 # 0.75 per 30 miningPoints: 16 materials: RawQuartz: 100 @@ -93,7 +93,7 @@ - type: latheRecipe id: SheetPlasma1 result: SheetPlasma1 - completetime: 0 + completetime: 0.0116 # 0.35 per 30 miningPoints: 15 materials: RawPlasma: 100 @@ -108,7 +108,7 @@ - type: latheRecipe id: SheetPlasteel1 result: SheetPlasteel1 - completetime: 0 + completetime: 0.025 # 0.75 per 30 miningPoints: 17 materials: RawPlasma: 100 @@ -134,7 +134,7 @@ - type: latheRecipe id: SheetUGlass1 result: SheetUGlass1 - completetime: 0 + completetime: 0.0083 # 0.25 per 30 miningPoints: 31 materials: RawUranium: 100 @@ -151,7 +151,7 @@ - type: latheRecipe id: SheetRUGlass1 result: SheetRUGlass1 - completetime: 0 + completetime: 0.025 # 0.75 per 30 miningPoints: 31 materials: RawUranium: 100 @@ -193,7 +193,7 @@ - type: latheRecipe id: MaterialDiamond result: MaterialDiamond1 - completetime: 0 + completetime: 0.026 # 0.8 over 30 miningPoints: 50 materials: RawDiamond: 100 @@ -201,7 +201,7 @@ - type: latheRecipe id: SheetUranium1 result: SheetUranium1 - completetime: 0 + completetime: 0.02 # 0.6 seconds for 30 miningPoints: 30 materials: RawUranium: 100 @@ -209,7 +209,7 @@ - type: latheRecipe id: IngotGold1 result: IngotGold1 - completetime: 0 + completetime: 0.016 # 0.5 over 30 miningPoints: 18 materials: RawGold: 100 @@ -217,7 +217,7 @@ - type: latheRecipe id: IngotSilver1 result: IngotSilver1 - completetime: 0 + completetime: 0.013 # 0.4 over 30 miningPoints: 16 materials: RawSilver: 100 @@ -233,7 +233,7 @@ - type: latheRecipe id: MaterialBananium1 result: MaterialBananium1 - completetime: 0 + completetime: 0.1 # 1 over 10 miningPoints: 60 materials: RawBananium: 100 @@ -291,7 +291,7 @@ result: IngotTungsten1 applyMaterialDiscount: false miningPoints: 5 - completetime: 4 + completetime: 0.13 # Or, 4 seconds over 30 ingots. materials: RawTungsten: 100 RawIron: 100 diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml b/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml index f4e44be33e..bc3253cd2b 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml @@ -21,6 +21,8 @@ - !type:AddComponentSpecial components: - type: ProfessionalChef #Nyano - End Summary. + - type: GrantCqc # Goobstation - Martial Arts + isBlocked: true # Goobstation - Martial Arts - type: startingGear id: ChefGear diff --git a/Resources/Prototypes/_EE/Entities/Structures/Doors/Airlocks/shuttleAirlocks.yml b/Resources/Prototypes/_EE/Entities/Structures/Doors/Airlocks/shuttleAirlocks.yml new file mode 100644 index 0000000000..981dd814bd --- /dev/null +++ b/Resources/Prototypes/_EE/Entities/Structures/Doors/Airlocks/shuttleAirlocks.yml @@ -0,0 +1,81 @@ +# Unlimited, these are targets for shuttles to dock to. +- type: entity + parent: AirlockGlassShuttle + id: AirlockExternalGlassShuttleCargoShuttle + suffix: External, Cargo, Glass, Docking + components: + - type: PriorityDock + tag: DockCargoShuttle + +- type: entity + parent: AirlockGlassShuttle + id: AirlockExternalGlassShuttleDart + suffix: External, ERT, Glass, Docking + components: + - type: PriorityDock + tag: DockDart + +- type: entity + parent: AirlockSyndicateGlass + id: AirlockSyndicateGlassShuttleInfiltrator + suffix: External, Infiltrator, Glass, Docking + components: + - type: PriorityDock + tag: DockInfiltrator + +- type: entity + parent: AirlockGlassShuttle + id: AirlockExternalGlassShuttlePathfinder + suffix: External, Salvage, Glass, Docking + components: + - type: PriorityDock + tag: DockPathfinder + +- type: entity + parent: AirlockSyndicateGlass + id: AirlockSyndicateGlassShuttleSANDropship + suffix: External, SAN Dropship, Glass, Docking + components: + - type: PriorityDock + tag: DockSANDropship + +# 1 per map, these spawn a shuttle. +- type: entity + parent: AirlockExternalGlassShuttleCargoShuttle + id: AirlockExternalGlassShuttleCargoShuttleFilled + suffix: Cargo Shuttle Spawner, MAX ONE PER MAP + components: + - type: GridFill + path: /Maps/Shuttles/cargo.yml + +- type: entity + parent: AirlockExternalGlassShuttleDart + id: AirlockExternalGlassShuttleDartFilled + suffix: ERT Ship Spawner, MAX ONE PER MAP + components: + - type: GridFill + path: /Maps/Shuttles/dart.yml + +- type: entity + parent: AirlockSyndicateGlassShuttleInfiltrator + id: AirlockSyndicateGlassShuttleInfiltratorFilled + suffix: Infiltrator Ship Spawner, MAX ONE PER MAP + components: + - type: GridFill + path: /Maps/Shuttles/infiltrator.yml + +- type: entity + parent: AirlockExternalGlassShuttlePathfinder + id: AirlockExternalGlassShuttlePathfinderFilled + suffix: Salvage Ship Spawner, MAX ONE PER MAP + components: + - type: GridFill + path: /Maps/Shuttles/pathfinder.yml + +- type: entity + parent: AirlockSyndicateGlassShuttleSANDropship + id: AirlockSyndicateGlassShuttleSANDropshipFilled + suffix: SAN Dropship Spawner, MAX ONE PER MAP + components: + - type: GridFill + path: /Maps/Shuttles/ShuttleEvent/SANDropship.yml diff --git a/Resources/Prototypes/_EE/Tags/tags.yml b/Resources/Prototypes/_EE/Tags/tags.yml new file mode 100644 index 0000000000..54e0ed6186 --- /dev/null +++ b/Resources/Prototypes/_EE/Tags/tags.yml @@ -0,0 +1,14 @@ +- type: Tag + id: DockCargoShuttle + +- type: Tag + id: DockDart + +- type: Tag + id: DockInfiltrator + +- type: Tag + id: DockPathfinder + +- type: Tag + id: DockSANDropship diff --git a/Resources/Prototypes/_Goobstation/Catalog/uplink_catalog.yml b/Resources/Prototypes/_Goobstation/Catalog/uplink_catalog.yml index c8c420f392..3dfb1ce9f4 100644 --- a/Resources/Prototypes/_Goobstation/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/_Goobstation/Catalog/uplink_catalog.yml @@ -37,6 +37,39 @@ tags: - NukeOpsUplink +# Martial Arts +- type: listing + id: UplinkCQCManual + name: uplink-cqc-name + description: uplink-cqc-desc + productEntity: CQCManual + # WD EDIT START + discountCategory: veryRareDiscounts + discountDownTo: + Telecrystal: 3 + cost: + Telecrystal: 12 + # WD EDIT END + categories: + - UplinkDeception + +- type: listing + id: UplinkMysteriousScroll + name: uplink-sleeping-carp-name + description: uplink-sleeping-carp-desc + productEntity: SleepingCarpScroll + # WD EDIT START + discountCategory: veryRareDiscounts + discountDownTo: + Telecrystal: 3 + cost: + Telecrystal: 14 + # WD EDIT END + categories: + - UplinkWeaponry + + +# Misc - type: listing id: UplinkHardsuitCybersunStealth name: uplink-hardsuit-cybersun-stealth-name diff --git a/Resources/Prototypes/_Goobstation/Entities/Clothing/Belt/belts.yml b/Resources/Prototypes/_Goobstation/Entities/Clothing/Belt/belts.yml new file mode 100644 index 0000000000..773e9863e9 --- /dev/null +++ b/Resources/Prototypes/_Goobstation/Entities/Clothing/Belt/belts.yml @@ -0,0 +1,33 @@ +- type: entity + parent: ClothingBeltSecurity + id: ClothingBeltCorporateJudo + name: Corporate Judo Belt + description: Teaches the wearer NT Corporate Judo. + components: + - type: Sprite + sprite: _Goobstation/Clothing/Belt/judobelt.rsi + - type: Clothing + sprite: _Goobstation/Clothing/Belt/judobelt.rsi + - type: GrantCorporateJudo + - type: Storage + whitelist: + tags: + - CigPack + - Taser + - SecBeltEquip + - Radio + - Sidearm + - MagazinePistol + - MagazineMagnum + - CombatKnife + - Truncheon + components: + - FlashOnTrigger + - SmokeOnTrigger + - Flash + - Handcuff + - BallisticAmmoProvider + - CartridgeAmmo + - DoorRemote + - Whistle + - BalloonPopper diff --git a/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Melee/kravmagagloves.yml b/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Melee/kravmagagloves.yml new file mode 100644 index 0000000000..bebe1b0aa9 --- /dev/null +++ b/Resources/Prototypes/_Goobstation/Entities/Objects/Weapons/Melee/kravmagagloves.yml @@ -0,0 +1,16 @@ +- type: entity + parent: ClothingHandsBase + id: ClothingHandsGlovesKravMaga + name: Krav Maga gloves + description: These gloves can teach you to perform Krav Maga using nanochips for as long as you're wearing them. + components: + - type: Sprite + sprite: _Goobstation/Clothing/Hands/Gloves/kravgloves.rsi + - type: Item + - type: Clothing + - type: Fiber + fiberMaterial: fibers-leather + fiberColor: fibers-red + - type: ClothingGrantComponent + component: + - type: KravMaga diff --git a/Resources/Prototypes/_Goobstation/Entities/Specific/bso.yml b/Resources/Prototypes/_Goobstation/Entities/Specific/bso.yml new file mode 100644 index 0000000000..d06fd232ff --- /dev/null +++ b/Resources/Prototypes/_Goobstation/Entities/Specific/bso.yml @@ -0,0 +1,15 @@ +- type: entity + parent: BaseItem + id: BSOManual + name: Nanotrasen CQC Manual + description: A small, blue manual. There are drawn instructions of tactical hand-to-hand combat. + components: + - type: Sprite + sprite: _Goobstation/Objects/Misc/cqc_manual.rsi + layers: + - state: icon-alt + - type: Item + size: Small + - type: StaticPrice + price: 3000 + - type: GrantCqc diff --git a/Resources/Prototypes/_Goobstation/Entities/Specific/syndicate.yml b/Resources/Prototypes/_Goobstation/Entities/Specific/syndicate.yml new file mode 100644 index 0000000000..051a109c72 --- /dev/null +++ b/Resources/Prototypes/_Goobstation/Entities/Specific/syndicate.yml @@ -0,0 +1,32 @@ +- type: entity + parent: BaseItem + id: CQCManual + name: old manual + description: A small, black manual. There are drawn instructions of tactical hand-to-hand combat. + components: + - type: Sprite + sprite: _Goobstation/Objects/Misc/cqc_manual.rsi + layers: + - state: icon + - type: Item + size: Small + - type: StaticPrice + price: 3000 + - type: GrantCqc + +- type: entity + parent: BaseItem + id: SleepingCarpScroll + name: mysterious scroll + description: A scroll filled with strange markings. It seems to be drawings of some sort of martial art. + components: + - type: Sprite + sprite: _Goobstation/Wizard/Objects/scroll.rsi + layers: + - state: scroll2 + - type: Item + sprite: _Goobstation/Wizard/Objects/scroll.rsi + size: Small + - type: StaticPrice + price: 3000 + - type: GrantSleepingCarp diff --git a/Resources/Prototypes/_Goobstation/MartialArts/carp.yml b/Resources/Prototypes/_Goobstation/MartialArts/carp.yml new file mode 100644 index 0000000000..67c3c66dad --- /dev/null +++ b/Resources/Prototypes/_Goobstation/MartialArts/carp.yml @@ -0,0 +1,64 @@ +- type: martialArt + id: SleepingCarp + martialArtsForm: SleepingCarp + roundstartCombos: SleepingCarpMoves + randomDamageModifier: True + baseDamageModifier: 5 + randomSayings: + - carp-saying-huah + - carv-saying-hya + - carp-saying-choo + - carp-saying-wuo + - carp-saying-kya + - carp-saying-huh + - carp-saying-hiyoh + - carp-saying-strike + - carp-saying-bite + randomSayingsDowned: + - carp-saying-banzai + - carp-saying-kiya + - carp-saying-omae + - carp-saying-see + - carp-saying-time + - carp-saying-cowabunga + +- type: comboList + id: SleepingCarpMoves + combos: + - SleepingCarpGnashingTeeth + - SleepingCarpKneeHaul + - SleepingCarpCrashingWaves + +- type: combo + id: SleepingCarpGnashingTeeth + name: Gnashing Teeth + martialArtsForm: SleepingCarp + attacks: + - Harm + - Harm + event: !type:SleepingCarpGnashingTeethPerformedEvent + damageType: Slash + extraDamage: 20 + +- type: combo + id: SleepingCarpKneeHaul + name: Knee Haul + martialArtsForm: SleepingCarp + attacks: + - Harm + - Grab + event: !type:SleepingCarpKneeHaulPerformedEvent + extraDamage: 10 + paralyzeTime: 6 + staminaDamage: 60 + +- type: combo + id: SleepingCarpCrashingWaves + name: Crashing Waves + martialArtsForm: SleepingCarp + attacks: + - Harm + - Disarm + event: !type:SleepingCarpCrashingWavesPerformedEvent + staminaDamage: 25 + diff --git a/Resources/Prototypes/_Goobstation/MartialArts/cqc.yml b/Resources/Prototypes/_Goobstation/MartialArts/cqc.yml new file mode 100644 index 0000000000..35edf58eb2 --- /dev/null +++ b/Resources/Prototypes/_Goobstation/MartialArts/cqc.yml @@ -0,0 +1,69 @@ +- type: martialArt + id: CloseQuartersCombat + martialArtsForm: CloseQuartersCombat + roundstartCombos: CQCMoves + +- type: comboList + id: CQCMoves + combos: + - CQCConsecutive + - CQCPressure + - CQCRestrain + - CQCKick + - CQCSlam + +- type: combo + id: CQCSlam + name: Slam + martialArtsForm: CloseQuartersCombat + attacks: + - Grab + - Harm + event: !type:CqcSlamPerformedEvent { } + extraDamage: 10 # + paralyzeTime: 12 # in seconds + + +- type: combo + id: CQCKick + name: Kick + martialArtsForm: CloseQuartersCombat + attacks: + - Harm + - Harm + event: !type:CqcKickPerformedEvent + extraDamage: 10 + staminaDamage: 55 + +- type: combo + id: CQCRestrain + name: Restrain + martialArtsForm: CloseQuartersCombat + attacks: + - Grab + - Grab + event: !type:CqcRestrainPerformedEvent + paralyzeTime: 10 + staminaDamage: 30 + +- type: combo + id: CQCPressure + name: Pressure + martialArtsForm: CloseQuartersCombat + attacks: + - Disarm + - Grab + event: !type:CqcPressurePerformedEvent + staminaDamage: 65 + +- type: combo + id: CQCConsecutive + name: Consecutive + martialArtsForm: CloseQuartersCombat + attacks: + - Disarm + - Disarm + - Harm + event: !type:CqcConsecutivePerformedEvent + extraDamage: 10 + staminaDamage: 70 diff --git a/Resources/Prototypes/_Goobstation/MartialArts/judo.yml b/Resources/Prototypes/_Goobstation/MartialArts/judo.yml new file mode 100644 index 0000000000..bb89f1fcc4 --- /dev/null +++ b/Resources/Prototypes/_Goobstation/MartialArts/judo.yml @@ -0,0 +1,45 @@ +- type: martialArt + id: CorporateJudo + martialArtsForm: CorporateJudo + roundstartCombos: CorporateJudoMoves + baseDamageModifier: 5 + +- type: comboList + id: CorporateJudoMoves + combos: + - JudoThrow + - JudoEyepoke + - JudoArmbar + +- type: combo + id: JudoThrow + name: Judo Throw + martialArtsForm: CorporateJudo + attacks: + - Grab + - Disarm + event: !type:JudoThrowPerformedEvent + staminaDamage: 50 + paralyzeTime: 7 + +- type: combo + id: JudoArmbar + name: Armbar + martialArtsForm: CorporateJudo + attacks: + - Disarm + - Disarm + - Grab + event: !type:JudoArmbarPerformedEvent + staminaDamage: 45 + paralyzeTime: 5 + +- type: combo + id: JudoEyepoke + name: Eyepoke + martialArtsForm: CorporateJudo + attacks: + - Disarm + - Harm + event: !type:JudoEyePokePerformedEvent + extraDamage: 5 diff --git a/Resources/Prototypes/_Goobstation/MartialArts/kravmaga.yml b/Resources/Prototypes/_Goobstation/MartialArts/kravmaga.yml new file mode 100644 index 0000000000..9998ce727a --- /dev/null +++ b/Resources/Prototypes/_Goobstation/MartialArts/kravmaga.yml @@ -0,0 +1,50 @@ +- type: entity + id: ActionLegSweep + name: Leg Sweep + description: Sweeps the legs out from under a target to knock them down for a few seconds. + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: _Goobstation/Actions/kravmaga.rsi + state: legsweep + useDelay: 3 + event: !type:KravMagaActionEvent { } + - type: KravMagaAction + configuration: LegSweep + name: Leg Sweep + +- type: entity + id: ActionNeckChop + name: Neck Chop + description: A hard swing with the side of your hand deals some damage and disables the target's ability to speak for twenty seconds + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: _Goobstation/Actions/kravmaga.rsi + state: neckchop + useDelay: 3 + event: !type:KravMagaActionEvent { } + - type: KravMagaAction + configuration: NeckChop + name: Neck Chop + effectTime: 20 + +- type: entity + id: ActionLungPunch + name: Lung Punch + description: Deals 30 stamina damage and prevents breathing for ten seconds. Four of those will incapacitate a target less-than-lethally, but beware of the loss of breath you cause. + categories: [ HideSpawnMenu ] + components: + - type: InstantAction + icon: + sprite: _Goobstation/Actions/kravmaga.rsi + state: lungpunch + useDelay: 3 + event: !type:KravMagaActionEvent { } + - type: KravMagaAction + configuration: LungPunch + name: Lung Punch + staminaDamage: 40 + effectTime: 10 diff --git a/Resources/Prototypes/_Nuclear14/Recipes/Lathes/materials.yml b/Resources/Prototypes/_Nuclear14/Recipes/Lathes/materials.yml index c15bc3244d..212714a548 100644 --- a/Resources/Prototypes/_Nuclear14/Recipes/Lathes/materials.yml +++ b/Resources/Prototypes/_Nuclear14/Recipes/Lathes/materials.yml @@ -3,14 +3,14 @@ result: N14IngotLead1 miningPoints: 10 applyMaterialDiscount: false - completetime: 2 + completetime: 0.01 # 0.3 per 30 materials: RawLead: 100 - type: latheRecipe id: IngotCopper1 result: IngotCopper1 - completetime: 2 + completetime: 0.016 # 0.5 per 30 miningPoints: 10 materials: RawCopper: 100 @@ -19,7 +19,7 @@ - type: latheRecipe id: N14IngotAluminium1 result: N14IngotAluminium1 - completetime: 2 + completetime: 0.016 # 0.5 per 30 miningPoints: 10 materials: RawAluminium: 100 diff --git a/Resources/Prototypes/_White/Entities/Clothing/Hands/gloves.yml b/Resources/Prototypes/_White/Entities/Clothing/Hands/gloves.yml index 7c4fd6a6a8..c4b2443ee2 100644 --- a/Resources/Prototypes/_White/Entities/Clothing/Hands/gloves.yml +++ b/Resources/Prototypes/_White/Entities/Clothing/Hands/gloves.yml @@ -19,31 +19,3 @@ sprite: _White/Clothing/Hands/sheriff_gloves.rsi - type: Clothing sprite: _White/Clothing/Hands/sheriff_gloves.rsi - -- type: entity - parent: ClothingHandsGlovesPowerglove - id: ClothingHandsGlovesPowergloveReal # WWDP HIGH RISK WARDEN GLOVES (fake krav magas) - name: power gloves - suffix: Powered - description: Now I'm playin' with power! BAM! - components: - - type: Insulated - - type: MeleeWeapon - autoAttack: true - attackRate: 0.5 - canHeavyAttack: false - maxTargets: 1 - damage: - types: - Blunt: 5 - soundHit: - collection: Punch - animation: WeaponArcFist - mustBeEquippedToUse: true - - type: StaminaDamageOnHit - damage: 25 - - type: Tag - tags: - - HighRiskItem - - type: StealTarget - stealGroup: WardenPowerGloves diff --git a/Resources/Prototypes/_White/Objectives/stealTargerGroups.yml b/Resources/Prototypes/_White/Objectives/stealTargerGroups.yml deleted file mode 100644 index f31ee3caa1..0000000000 --- a/Resources/Prototypes/_White/Objectives/stealTargerGroups.yml +++ /dev/null @@ -1,6 +0,0 @@ -- type: stealTargetGroup - id: WardenPowerGloves - name: steal-target-power-gloves - sprite: - sprite: Clothing/Hands/Gloves/powerglove.rsi - state: icon diff --git a/Resources/Prototypes/_White/Objectives/traitor.yml b/Resources/Prototypes/_White/Objectives/traitor.yml deleted file mode 100644 index 9c31850f43..0000000000 --- a/Resources/Prototypes/_White/Objectives/traitor.yml +++ /dev/null @@ -1,11 +0,0 @@ -- type: entity - categories: [HideSpawnMenu] - parent: BaseTraitorStealObjective - id: PowerGlovesStealObjective - components: - - type: NotJobRequirement - job: Warden - - type: StealCondition - stealGroup: WardenPowerGloves - verifyMapExistence: true - owner: job-name-warden diff --git a/Resources/Textures/DeltaV/Clothing/Hands/Gloves/inspection.rsi/meta.json b/Resources/Textures/DeltaV/Clothing/Hands/Gloves/inspection.rsi/meta.json index 89b3fb1d12..17ac407320 100644 --- a/Resources/Textures/DeltaV/Clothing/Hands/Gloves/inspection.rsi/meta.json +++ b/Resources/Textures/DeltaV/Clothing/Hands/Gloves/inspection.rsi/meta.json @@ -23,4 +23,4 @@ "directions": 4 } ] -} +} \ No newline at end of file diff --git a/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/legsweep.png b/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/legsweep.png new file mode 100644 index 0000000000..33c3f611c9 Binary files /dev/null and b/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/legsweep.png differ diff --git a/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/lungpunch.png b/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/lungpunch.png new file mode 100644 index 0000000000..047aed4309 Binary files /dev/null and b/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/lungpunch.png differ diff --git a/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/meta.json b/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/meta.json new file mode 100644 index 0000000000..31cbad53ff --- /dev/null +++ b/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/meta.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/a5726efe0c300662cb6f3a4a12d9151aa3eabe78/icons/mob/actions/actions.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "legsweep" + }, + { + "name": "lungpunch" + }, + { + "name": "neckchop" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/neckchop.png b/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/neckchop.png new file mode 100644 index 0000000000..8ef2373bbe Binary files /dev/null and b/Resources/Textures/_Goobstation/Actions/kravmaga.rsi/neckchop.png differ diff --git a/Resources/Textures/_Goobstation/Clothing/Belt/judobelt.rsi/equipped-BELT.png b/Resources/Textures/_Goobstation/Clothing/Belt/judobelt.rsi/equipped-BELT.png new file mode 100644 index 0000000000..09935e7c09 Binary files /dev/null and b/Resources/Textures/_Goobstation/Clothing/Belt/judobelt.rsi/equipped-BELT.png differ diff --git a/Resources/Textures/_Goobstation/Clothing/Belt/judobelt.rsi/icon.png b/Resources/Textures/_Goobstation/Clothing/Belt/judobelt.rsi/icon.png new file mode 100644 index 0000000000..2975449986 Binary files /dev/null and b/Resources/Textures/_Goobstation/Clothing/Belt/judobelt.rsi/icon.png differ diff --git a/Resources/Textures/_Goobstation/Clothing/Belt/judobelt.rsi/meta.json b/Resources/Textures/_Goobstation/Clothing/Belt/judobelt.rsi/meta.json new file mode 100644 index 0000000000..86066df528 --- /dev/null +++ b/Resources/Textures/_Goobstation/Clothing/Belt/judobelt.rsi/meta.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/7da09f5e7230369ec48d9e5d31bdddb3f95a6d8f/icons/mob/clothing/belt.dmi, https://github.com/ParadiseSS13/Paradise/blob/7da09f5e7230369ec48d9e5d31bdddb3f95a6d8f/icons/obj/clothing/belts.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "equipped-BELT", + "directions": 4 + }, + { + "name": "icon" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/_Goobstation/Clothing/Hands/Gloves/kravgloves.rsi/equipped-HAND.png b/Resources/Textures/_Goobstation/Clothing/Hands/Gloves/kravgloves.rsi/equipped-HAND.png new file mode 100644 index 0000000000..6d4e42c4cd Binary files /dev/null and b/Resources/Textures/_Goobstation/Clothing/Hands/Gloves/kravgloves.rsi/equipped-HAND.png differ diff --git a/Resources/Textures/_Goobstation/Clothing/Hands/Gloves/kravgloves.rsi/icon.png b/Resources/Textures/_Goobstation/Clothing/Hands/Gloves/kravgloves.rsi/icon.png new file mode 100644 index 0000000000..78a7b892d1 Binary files /dev/null and b/Resources/Textures/_Goobstation/Clothing/Hands/Gloves/kravgloves.rsi/icon.png differ diff --git a/Resources/Textures/_Goobstation/Clothing/Hands/Gloves/kravgloves.rsi/meta.json b/Resources/Textures/_Goobstation/Clothing/Hands/Gloves/kravgloves.rsi/meta.json new file mode 100644 index 0000000000..28854c9bcd --- /dev/null +++ b/Resources/Textures/_Goobstation/Clothing/Hands/Gloves/kravgloves.rsi/meta.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bd91a1b962fe9bd38e346e9fafd4ebb10784fcb3/icons/mob/clothing/hands.dmi and https://github.com/ParadiseSS13/Paradise/blob/bd91a1b962fe9bd38e346e9fafd4ebb10784fcb3/icons/obj/clothing/gloves.dmi and https://github.com/ParadiseSS13/Paradise/blob/HEAD/icons/mob/clothing/hands.dmi ", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HAND", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/_Goobstation/Objects/Misc/cqc_manual.rsi/icon-alt.png b/Resources/Textures/_Goobstation/Objects/Misc/cqc_manual.rsi/icon-alt.png new file mode 100644 index 0000000000..f01ed13e7e Binary files /dev/null and b/Resources/Textures/_Goobstation/Objects/Misc/cqc_manual.rsi/icon-alt.png differ diff --git a/Resources/Textures/_Goobstation/Objects/Misc/cqc_manual.rsi/icon.png b/Resources/Textures/_Goobstation/Objects/Misc/cqc_manual.rsi/icon.png new file mode 100644 index 0000000000..059c565fc5 Binary files /dev/null and b/Resources/Textures/_Goobstation/Objects/Misc/cqc_manual.rsi/icon.png differ diff --git a/Resources/Textures/_Goobstation/Objects/Misc/cqc_manual.rsi/meta.json b/Resources/Textures/_Goobstation/Objects/Misc/cqc_manual.rsi/meta.json new file mode 100644 index 0000000000..0371deee2a --- /dev/null +++ b/Resources/Textures/_Goobstation/Objects/Misc/cqc_manual.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprite taken at: https://github.com/tgstation/tgstation", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "icon-alt" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/equipped-BELT.png b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/equipped-BELT.png new file mode 100644 index 0000000000..9dc2b59ac8 Binary files /dev/null and b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/equipped-BELT.png differ diff --git a/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/inhand-left.png b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/inhand-left.png new file mode 100644 index 0000000000..ed1902af96 Binary files /dev/null and b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/inhand-left.png differ diff --git a/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/inhand-right.png b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/inhand-right.png new file mode 100644 index 0000000000..a1db789ce4 Binary files /dev/null and b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/inhand-right.png differ diff --git a/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/meta.json b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/meta.json new file mode 100644 index 0000000000..098f421f0d --- /dev/null +++ b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/80ab61c8c7741e1d95e5f168357a9e6e61b38f2c", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "scroll" + }, + { + "name": "scroll2" + }, + { + "name": "equipped-BELT", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/scroll.png b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/scroll.png new file mode 100644 index 0000000000..e7780ff2ca Binary files /dev/null and b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/scroll.png differ diff --git a/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/scroll2.png b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/scroll2.png new file mode 100644 index 0000000000..2f00a23401 Binary files /dev/null and b/Resources/Textures/_Goobstation/Wizard/Objects/scroll.rsi/scroll2.png differ