Upstream 08.03-09.03 (#299)
* Grabbing Fixes / Table Slam (#1889)
# Description
Ports several fixes + Tabling from
[/Goob-Station#1922](https://github.com/Goob-Station/Goob-Station/pull/1922)
Tabling is pretty much 1:1 with how it is from SS13
## This shit is so code
Required before I can port [Martial
Arts](https://github.com/Goob-Station/Goob-Station/pull/1868)
# TODO
* [ ] Await merge
* [ ] Gaming
# Media

# Changelog
🆑 Eagle
* add: Table slamming. Harm a table when you have someone harm choked,
see what happens.
* tweak: Grab throw damage to other entities is now based on the thrown
entities kinetic energy. No more mouse wrecking balls.
* tweak: You can now escape from a soft grab by just walking away.
* tweak: You can no longer grab someone else while your being grabbed.
* tweak: Mass now effects grab release attempts.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Introduced a table slam mechanic that brings dynamic combat
interactions. Characters and objects can now be “tabled” with associated
damage, stamina effects, and paralysis chance.
- Added new interactive states for pullable entities, enriching
environmental and combat engagements.
- **Gameplay Improvements**
- Refined pulling and throwing mechanics to enhance collision handling
and damage calculations, resulting in more impactful throw actions and
balanced kinetic responses.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
(cherry picked from commit 71147f8295c5c817b56d52c5d2a38acced2f14b9)
* Automatic Changelog Update (#1889)
(cherry picked from commit 434ce42a8a0739ff0873c4c02bfe83ed39c857e9)
* Fix UI Crap (#1888)
I have no idea if this fixes the issues, and I have not checked if it
does. But this is the only thing we're missing that wasn't related to
other unrelated stuff.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Bug Fixes**
- Improved the initialization process for several in-game user
interfaces, ensuring that all essential functionalities load
consistently when accessed.
- **New Features**
- Enhanced the voice mask configuration panel to automatically present
available speech verb options, streamlining the setup process for users.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Milon <milonpl.git@proton.me>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
(cherry picked from commit e2fbebba312a01d9fb92eaac64190df503607f6b)
* Shuttle Spawner Airlocks (#1890)
# Description
This PR adds a variety of "Shuttle Spawning Airlocks" for certain ships
in this game that mappers might wish to use. The most important of which
are airlocks that cause a Cargo Shuttle and a Pathfinder to spawn
already docked to the station. The fact that nobody did this before was
fucking astounding to me.
# Changelog
🆑
- add: 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.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Introduced a refined docking and spawning system for shuttle
operations, incorporating multiple shuttle types including cargo, dart,
infiltrator, pathfinder, and SANDropship.
- Added dedicated deployment entities to manage shuttle instantiation
effectively.
- Rolled out a new tagging framework to enhance the categorization and
identification of dockable vehicles.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
(cherry picked from commit 2f9239f6b0918fbdca1f0c48a06c3b3b76a11ab8)
* Automatic Changelog Update (#1890)
(cherry picked from commit 39eb098ebe3fcf7f283f46fadfc76545c20e667c)
* Update Credits (#1854)
This is an automated Pull Request. This PR updates the GitHub
contributors in the credits section.
Co-authored-by: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
(cherry picked from commit ad2ebc04093388d29db758fd7e632744e4d728d8)
* Remove Outdated Description From Flash, Add One to the New Disabler A… (#1887)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->
# Description
<!--
Explain this PR in as much detail as applicable
Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->
Accidentally left an old ExtendDescription on a flash which is no longer
accurate, and added extra descriptions to the rev manifesto and civilian
disabler while I was at it.
---
# Changelog
<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->
🆑
- add: Added extra descriptions to the revolutionary manifesto and the
civilian disabler
- fix: Fixed extenddescription on flash
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Introduced extended, context-sensitive in-game descriptions for the
revolutionary manifesto, offering nuanced details about its use across
various roles.
- Added enhanced descriptive information for the civilian disabler
weapon, clarifying its legal ownership and accessory considerations.
- **Chores**
- Streamlined the flash item display by removing redundant extended
descriptions to improve clarity.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Signed-off-by: Timfa <timfalken@hotmail.com>
(cherry picked from commit 3e3bee060cb7eee98ae3fde7c4f7b819f16bf840)
* Automatic Changelog Update (#1887)
(cherry picked from commit 4af6dc83bd2ebded1421dadea70b6a9586776fda)
* NewMats Lathe Recipe Changes (#1873)
# Description
<!--
Explain this PR in as much detail as applicable
Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->
Removes wait times from Copper, Lead, and Aluminum and reduces the wait
time for Tungsten to 0.13 (4 seconds over 30 ingots, too rare for it to
have no completiontime but too much completiontime for just one ingot).
It seems pretty ridiculous to make the former 3 recipes have a wait time
of TWO SECONDS PER INDIVIDUAL INGOT (which presents a lot of problems in
practice for salvagers) in comparison to the standard ore recipes which
have 0 wait times at all.
if the wait times are intentional then I would like you to consider
reducing them to something similar to what I did with the Tungsten- with
X seconds over 30 (or any other standard amount) ingots
---
# Changelog
🆑
- tweak: the Ore Processors now process Lead, Copper, and Aluminum
instantly, and is much faster at processing Tungsten
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Chores**
- Adjusted lathe production times for several recipes, resulting in more
accurate processing durations.
- The tungsten-based recipe now completes significantly faster (0.13
seconds versus 4 seconds).
- Three metal-based recipes have been updated to finish in shorter
durations (0.01 to 0.016 seconds).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
(cherry picked from commit d295e2535f9aa21497460279d0bfe108920c445b)
* Automatic Changelog Update (#1873)
(cherry picked from commit 8deed0c3c9d16ff0cdb956fc0ee457a5bf14f5ed)
* Revert "[Add] High-Risk Loadout Item For Warden: Power Gloves (#252)"
This reverts commit 1f936feaa8.
* Grab Intent Part 2: Martial Arts (#1891)
# Description
Finally, after 9 years in development, CQC is here.
Traitors can buy a CQC manual in the uplink, giving them access to
unarmed combos, and instant hardgrabs.
Traitors can also buy a Sleeping Carp Scroll, giving them 3 different
unarmed combos, and the ability to deflect all incoming projectiles, at
the cost of no longer being able to use ranged weapons.
The Chef can use Close-Quarters-Cooking while in the kitchen. Tiders
beware.
Security officers also have access to a Corporate Judo Belt as an
alternative to the stun baton.
The Warden starts with Krav Maga gloves in his locker, with 3 different
attacks.
## This code is, not shit perhaps?
Ports martial arts from
[/Goob-Station#1868](https://github.com/Goob-Station/Goob-Station/pull/1868)
All seems pretty well written, shouldn't be hard to add new ones in the
future.
There also exists a version of the CQC manual for the BSO. Might add to
the BSO locker if requested.
# TODO
* [x] Await reviews
* [x] Pain
# Media
Judo
https://github.com/user-attachments/assets/b0aa4d24-f5cd-478e-8358-a095d46a4572
CQC
https://youtu.be/c0EJfbwqil8
Sleeping Carp
https://github.com/user-attachments/assets/a16ec334-9f9a-4820-b4f1-32a0cc598c67
https://github.com/user-attachments/assets/3e2bfc95-7c92-46f6-9b7c-b1e6596540c7
# Changelog
🆑 Eagle
* add: Added Corporate Judo, CQC, Sleeping Carp, and Krav Maga martial
arts with unique abilities.
* add: The Chef has been given Close Quarters Cooking in the Kitchen and
Bar. Tiders beware.
---------
Signed-off-by: Eagle-0 <114363363+Eagle-0@users.noreply.github.com>
(cherry picked from commit 68872f85c8b2227e871667caed2289042edd0d7b)
* Automatic Changelog Update (#1891)
(cherry picked from commit 9e3ad56873aedb7a7d0fff6037f9aaf0026897c0)
* Bug Fix: Fix Roboticist Airlock Sprite Error (#1899)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->
# Description
Description.
A fix for [this
issue](https://github.com/Simple-Station/Einstein-Engines/issues/1872)
Fixed bug of the painted roboticist airlock displaying the windowed
counterpart instead of the standard one.
# TODO
<!--
A list of everything you have to do before this PR is "complete"
You probably won't have to complete everything before merging but it's
good to leave future references
-->
- [ ] Task
- [x] Completed Task
---
<!--
This is default collapsed, readers click to expand it and see all your
media
The PR media section can get very large at times, so this is a good way
to keep it clean
The title is written using HTML tags
The title must be within the <summary> tags or you won't see it
-->
<details><summary><h1>Media</h1></summary>
https://github.com/user-attachments/assets/fbe4c85f-c876-4e29-9c8d-cf95314e737f
</details>
---
# Changelog
<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->
🆑
- fix: Fixed bug of the painted roboticist airlock displaying the
windowed counterpart instead of the standard one.
(cherry picked from commit a3b823b0059a67767f0adf27ec65151d2f73a1fd)
* Automatic Changelog Update (#1899)
(cherry picked from commit ca839d18fbcdb85d4d1e60f2acad68fda02e1634)
* Fixes SM Being Started on Round Start (#1901)
# Description
To stop the SM from getting activated without something being thrown
into the SM or by having emitters hit the SM.
---
# TODO
- [x] Fix the SM by starting on its own.
---
# Changelog
🆑
- fix: SM no longer starts on round start.
- fix: SM will no longer delam from spacing unless it's activated.
---------
Co-authored-by: Nathaniel Adams <60526456+Nathaniel-Adams@users.noreply.github.com>
(cherry picked from commit 234ac6119f999ff2bfaabee6b93b5fa75c61c0fa)
* Automatic Changelog Update (#1901)
(cherry picked from commit 3a0c67ba9c6aa8341e9bfd529bb58818164e20c8)
* Tc rebalance
---------
Co-authored-by: Eagle-0 <114363363+Eagle-0@users.noreply.github.com>
Co-authored-by: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Co-authored-by: VMSolidus <evilexecutive@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Timfa <timfalken@hotmail.com>
Co-authored-by: RadsammyT <32146976+RadsammyT@users.noreply.github.com>
Co-authored-by: Paulo Artur Pinheiro Viana Villaça <112904295+AlgumCorrupto@users.noreply.github.com>
Co-authored-by: Solaris <60526456+SolarisBirb@users.noreply.github.com>
@@ -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;
|
||||
|
||||
@@ -41,6 +41,8 @@ namespace Content.Client.Instruments.UI
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_instrumentMenu = this.CreateWindow<InstrumentMenu>();
|
||||
_instrumentMenu.Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName;
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ public sealed class NewsWriterBoundUserInterface : BoundUserInterface
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<NewsWriterMenu>();
|
||||
|
||||
_menu.ArticleEditorPanel.PublishButtonPressed += OnPublishButtonPressed;
|
||||
|
||||
@@ -14,6 +14,8 @@ public sealed class CrewMonitoringBoundUserInterface : BoundUserInterface
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
EntityUid? gridUid = null;
|
||||
var stationName = string.Empty;
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace Content.Client.Nuke
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<NukeMenu>();
|
||||
|
||||
_menu.OnKeypadButtonPressed += i =>
|
||||
|
||||
@@ -12,6 +12,8 @@ public sealed class PowerMonitoringConsoleBoundUserInterface : BoundUserInterfac
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<PowerMonitoringWindow>();
|
||||
_menu.SetEntity(Owner);
|
||||
_menu.SendPowerMonitoringConsoleMessageAction += SendPowerMonitoringConsoleMessage;
|
||||
|
||||
@@ -27,6 +27,8 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<StoreMenu>();
|
||||
if (EntMan.TryGetComponent<StoreComponent>(Owner, out var store))
|
||||
_menu.Title = Loc.GetString(store.Name);
|
||||
|
||||
@@ -21,6 +21,8 @@ public sealed class SurveillanceCameraSetupBoundUi : BoundUserInterface
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = new();
|
||||
|
||||
if (_type == SurveillanceCameraSetupUiKey.Router)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
10
Content.Client/_Goobstation/MartialArts/MartialArtsSystem.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Content.Shared._Goobstation.MartialArts;
|
||||
|
||||
namespace Content.Client._Goobstation.MartialArts;
|
||||
|
||||
/// <summary>
|
||||
/// This handles...
|
||||
/// </summary>
|
||||
public sealed class MartialArtsSystem : SharedMartialArtsSystem
|
||||
{
|
||||
}
|
||||
@@ -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<PullableComponent>(uid, out var pullable) || pullable.GrabStage != GrabStage.Suffocate;
|
||||
if (TryComp<PullableComponent>(uid, out var pullable)
|
||||
&& pullable.GrabStage == GrabStage.Suffocate)
|
||||
return false;
|
||||
|
||||
return !HasComp<KravMagaBlockedBreathingComponent>(uid);
|
||||
}
|
||||
// Goobstation end
|
||||
private void OnMapInit(Entity<RespiratorComponent> ent, ref MapInitEvent args)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -78,6 +78,9 @@ public sealed partial class SupermatterSystem : EntitySystem
|
||||
|
||||
foreach (var sm in EntityManager.EntityQuery<SupermatterComponent>())
|
||||
{
|
||||
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);
|
||||
|
||||
26
Content.Server/_Goobstation/MartialArts/MartialArtsSystem.cs
Normal file
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Just handles carp sayings for now.
|
||||
/// </summary>
|
||||
public sealed class MartialArtsSystem : SharedMartialArtsSystem
|
||||
{
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<CanPerformComboComponent, SleepingCarpSaying>(OnSleepingCarpSaying);
|
||||
}
|
||||
|
||||
private void OnSleepingCarpSaying(Entity<CanPerformComboComponent> ent, ref SleepingCarpSaying args)
|
||||
{
|
||||
_chat.TrySendInGameICMessage(ent, Loc.GetString(args.Saying), InGameICChatType.Speak, false);
|
||||
}
|
||||
}
|
||||
@@ -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<MartialArtsKnowledgeComponent>(args.User, out var knowledgeComp)
|
||||
&& TryComp<MartialArtBlockedComponent>(args.Weapon, out var blockedComp)
|
||||
&& knowledgeComp.MartialArtsForm == blockedComp.Form)
|
||||
return;
|
||||
// Goobstation
|
||||
|
||||
var ev = new StaminaDamageOnHitAttemptEvent();
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
if (ev.Cancelled)
|
||||
|
||||
@@ -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 <see cref="PullerComponent"/>
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(Systems.PullingSystem))]
|
||||
[Access(typeof(Systems.PullingSystem), typeof(TableSlamSystem))]
|
||||
public sealed partial class PullableComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
@@ -57,6 +58,30 @@ public sealed partial class PullableComponent : Component
|
||||
|
||||
[AutoNetworkedField]
|
||||
public TimeSpan NextEscapeAttempt = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// If this pullable being tabled.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool BeingTabled = false;
|
||||
|
||||
/// <summary>
|
||||
/// Constant for tabling throw math
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float BasedTabledForceSpeed = 5f;
|
||||
|
||||
/// <summary>
|
||||
/// Stamina damage. taken on tabled
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float TabledStaminaDamage = 40f;
|
||||
|
||||
/// <summary>
|
||||
/// Damage taken on being tabled.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float TabledDamage = 5f;
|
||||
// Goobstation end
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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;
|
||||
/// <summary>
|
||||
/// Specifies an entity as being able to pull another entity with <see cref="PullableComponent"/>
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(PullingSystem))]
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
||||
[Access(typeof(PullingSystem), typeof(TableSlamSystem))] // Goobstation - Table Slam
|
||||
public sealed partial class PullerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
@@ -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<EntityUid> GrabVirtualItems = new();
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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<PullerComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
||||
SubscribeLocalEvent<PullerComponent, DropHandItemsEvent>(OnDropHandItems);
|
||||
SubscribeLocalEvent<PullerComponent, VirtualItemThrownEvent>(OnVirtualItemThrown); // Goobstation - Grab Intent
|
||||
SubscribeLocalEvent<PullerComponent, VirtualItemDropAttemptEvent>(OnVirtualItemDropAttempt); // Goobstation - Grab Intent
|
||||
SubscribeLocalEvent<PullerComponent, AddCuffDoAfterEvent>(OnAddCuffDoAfterEvent); // Goobstation - Grab Intent
|
||||
|
||||
SubscribeLocalEvent<PullableComponent, StrappedEvent>(OnBuckled);
|
||||
@@ -117,7 +117,6 @@ public sealed class PullingSystem : EntitySystem
|
||||
.Bind(ContentKeyFunctions.ReleasePulledObject, InputCmdHandler.FromDelegate(OnReleasePulledObject, handle: false))
|
||||
.Register<PullingSystem>();
|
||||
}
|
||||
|
||||
// Goobstation - Grab Intent
|
||||
private void OnAddCuffDoAfterEvent(Entity<PullerComponent> 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<PullerComponent> 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<GrabThrownComponent>(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<VirtualItemComponent>(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<PhysicsComponent>(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<GrabThrownComponent>(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<PullableComponent> 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<PullableComponent>(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<VirtualItemComponent>(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
|
||||
|
||||
@@ -155,6 +155,7 @@ public sealed class ThrowingSystem : EntitySystem
|
||||
{
|
||||
Thrower = user,
|
||||
Animate = animated,
|
||||
|
||||
};
|
||||
|
||||
// if not given, get the default friction value for distance calculation
|
||||
|
||||
@@ -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<CombatModeComponent>(user, out var combatMode) ||
|
||||
combatMode.CanDisarm == false) // WWDP
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ public sealed partial class SupermatterComponent : Component
|
||||
/// The SM will only cycle if activated.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool Activated = true;
|
||||
public bool Activated = false;
|
||||
|
||||
/// <summary>
|
||||
/// The current status of the singularity, used for alert sounds and the monitoring console
|
||||
|
||||
70
Content.Shared/_Goobstation/MartialArts/ComboPrototype.cs
Normal file
@@ -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<ComboAttackType> AttackTypes = new();
|
||||
|
||||
//[DataField("weapon")] // Will be done later
|
||||
//public string? WeaponProtoId;
|
||||
[DataField("event", required: true)]
|
||||
public object? ResultEvent;
|
||||
|
||||
/// <summary>
|
||||
/// How much extra damage should this move do on perform?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int ExtraDamage;
|
||||
|
||||
/// <summary>
|
||||
/// Stun time in seconds
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int ParalyzeTime;
|
||||
|
||||
/// <summary>
|
||||
/// How much stamina damage should this move do on perform.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float StaminaDamage;
|
||||
|
||||
/// <summary>
|
||||
/// Blunt, Slash, etc.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string DamageType = "Blunt";
|
||||
|
||||
/// <summary>
|
||||
/// How fast people are thrown on combo
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float ThrownSpeed = 7f;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the move
|
||||
/// </summary>
|
||||
[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<ProtoId<ComboPrototype>> Combos = new();
|
||||
}
|
||||
@@ -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<ComboPrototype> BeingPerformed;
|
||||
|
||||
[DataField]
|
||||
public List<ComboAttackType> LastAttacks = new();
|
||||
|
||||
[DataField]
|
||||
public List<ComboPrototype> AllowedCombos = new();
|
||||
|
||||
[DataField]
|
||||
public List<ProtoId<ComboPrototype>> RoundstartCombos = new();
|
||||
|
||||
[DataField]
|
||||
public TimeSpan ResetTime = TimeSpan.Zero;
|
||||
|
||||
[DataField]
|
||||
public int ConsecutiveGnashes = 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Content.Shared.Movement.Pulling.Systems;
|
||||
|
||||
namespace Content.Shared._Goobstation.MartialArts.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Base component for martial arts that override the normal grab stages.
|
||||
/// Allows martial arts to start at more advanced grab stages like Hard grabs.
|
||||
/// </summary>
|
||||
public abstract partial class GrabStagesOverrideComponent : Component
|
||||
{
|
||||
public GrabStage StartingStage = GrabStage.Hard;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._Goobstation.MartialArts.Components;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for...
|
||||
/// </summary>
|
||||
[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<EntProtoId> BaseKravMagaMoves = new()
|
||||
{
|
||||
"ActionLegSweep",
|
||||
"ActionNeckChop",
|
||||
"ActionLungPunch",
|
||||
};
|
||||
|
||||
public readonly List<EntityUid> KravMagaMoveEntities = new()
|
||||
{
|
||||
};
|
||||
|
||||
[DataField]
|
||||
public int BaseDamage = 5;
|
||||
|
||||
[DataField]
|
||||
public int DownedDamageModifier = 2;
|
||||
}
|
||||
/// <summary>
|
||||
/// Tracks when an entity is silenced through Krav Maga techniques.
|
||||
/// Prevents the affected entity from using voice-activated abilities or speaking.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class KravMagaSilencedComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public TimeSpan SilencedTime = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracks when an entity's breathing is blocked through Krav Maga techniques.
|
||||
/// May cause suffocation damage over time when integrated with respiration systems.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class KravMagaBlockedBreathingComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public TimeSpan BlockedTime = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
public enum KravMagaMoves
|
||||
{
|
||||
LegSweep,
|
||||
NeckChop,
|
||||
LungPunch,
|
||||
}
|
||||
@@ -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<ComboListPrototype> RoundstartCombos = "CQCMoves";
|
||||
|
||||
[DataField]
|
||||
[AutoNetworkedField]
|
||||
public bool Blocked = false;
|
||||
|
||||
[DataField]
|
||||
[AutoNetworkedField]
|
||||
public List<LocId> RandomSayings = [];
|
||||
|
||||
[DataField]
|
||||
[AutoNetworkedField]
|
||||
public List<LocId> RandomSayingsDowned = [];
|
||||
}
|
||||
|
||||
public enum MartialArtsForms
|
||||
{
|
||||
CorporateJudo,
|
||||
CloseQuartersCombat,
|
||||
SleepingCarp,
|
||||
}
|
||||
18
Content.Shared/_Goobstation/MartialArts/Events/CQCEvents.cs
Normal file
@@ -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;
|
||||
@@ -0,0 +1,30 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._Goobstation.MartialArts.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a martial arts combo attack is performed. Contains information about
|
||||
/// the performer, target, weapon used, and the type of combo attack.
|
||||
/// </summary>
|
||||
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,
|
||||
}
|
||||
@@ -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<ComboPrototype> protoId) : EntityEventArgs
|
||||
{
|
||||
public ProtoId<ComboPrototype> ProtoId = protoId;
|
||||
}
|
||||
16
Content.Shared/_Goobstation/MartialArts/Events/JudoEvents.cs
Normal file
@@ -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;
|
||||
@@ -0,0 +1,10 @@
|
||||
using Content.Shared.Actions;
|
||||
|
||||
namespace Content.Shared._Goobstation.MartialArts.Events;
|
||||
|
||||
/// <summary>
|
||||
/// This handles selecting your krav maga action
|
||||
/// </summary>
|
||||
public sealed partial class KravMagaActionEvent : InstantActionEvent
|
||||
{
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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<ComboListPrototype> RoundstartCombos = "CQCMoves";
|
||||
|
||||
[DataField]
|
||||
public List<LocId> RandomSayings = [];
|
||||
|
||||
[DataField]
|
||||
public List<LocId> RandomSayingsDowned = [];
|
||||
}
|
||||
@@ -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<CanPerformComboComponent, CqcSlamPerformedEvent>(OnCQCSlam);
|
||||
SubscribeLocalEvent<CanPerformComboComponent, CqcKickPerformedEvent>(OnCQCKick);
|
||||
SubscribeLocalEvent<CanPerformComboComponent, CqcRestrainPerformedEvent>(OnCQCRestrain);
|
||||
SubscribeLocalEvent<CanPerformComboComponent, CqcPressurePerformedEvent>(OnCQCPressure);
|
||||
SubscribeLocalEvent<CanPerformComboComponent, CqcConsecutivePerformedEvent>(OnCQCConsecutive);
|
||||
SubscribeLocalEvent<MartialArtsKnowledgeComponent, ComboAttackPerformedEvent>(OnCQCAttackPerformed);
|
||||
|
||||
SubscribeLocalEvent<GrantCqcComponent, UseInHandEvent>(OnGrantCQCUse);
|
||||
SubscribeLocalEvent<GrantCqcComponent, MapInitEvent>(OnMapInitEvent);
|
||||
SubscribeLocalEvent<GrantCqcComponent, ExaminedEvent>(OnGrantCQCExamine);
|
||||
}
|
||||
|
||||
|
||||
#region Generic Methods
|
||||
|
||||
private void OnMapInitEvent(Entity<GrantCqcComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
if (!HasComp<MobStateComponent>(ent))
|
||||
return;
|
||||
|
||||
if (!TryGrant(ent.Comp, ent))
|
||||
return;
|
||||
|
||||
if (TryComp<MartialArtsKnowledgeComponent>(ent, out var knowledge))
|
||||
knowledge.Blocked = true;
|
||||
}
|
||||
|
||||
private void OnGrantCQCUse(Entity<GrantCqcComponent> 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<GrantCqcComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (ent.Comp.Used)
|
||||
args.PushMarkup(Loc.GetString("cqc-manual-used", ("manual", Identity.Entity(ent, EntityManager))));
|
||||
}
|
||||
|
||||
private void OnCQCAttackPerformed(Entity<MartialArtsKnowledgeComponent> ent, ref ComboAttackPerformedEvent args)
|
||||
{
|
||||
if (!TryComp<MartialArtsKnowledgeComponent>(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<RequireProjectileTargetComponent>(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<CanPerformComboComponent> 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<PullableComponent>(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<CanPerformComboComponent> 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<StaminaComponent>(target, out var stamina) && stamina.Critical)
|
||||
{
|
||||
_status.TryAddStatusEffect<ForcedSleepingComponent>(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<PullableComponent>(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<CanPerformComboComponent> 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<CanPerformComboComponent> 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<CanPerformComboComponent> 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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// This handles determining if a combo was performed.
|
||||
/// </summary>
|
||||
public partial class SharedMartialArtsSystem
|
||||
{
|
||||
private void InitializeCanPerformCombo()
|
||||
{
|
||||
SubscribeLocalEvent<CanPerformComboComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<CanPerformComboComponent, ComboAttackPerformedEvent>(OnAttackPerformed);
|
||||
SubscribeLocalEvent<CanPerformComboComponent, ComboBeingPerformedEvent>(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<MobStateComponent>(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<CanPerformComboComponent> ent, ref ComboBeingPerformedEvent args)
|
||||
{
|
||||
ent.Comp.BeingPerformed = args.ProtoId;
|
||||
Dirty(ent, ent.Comp);
|
||||
}
|
||||
}
|
||||
@@ -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<CanPerformComboComponent, JudoThrowPerformedEvent>(OnJudoThrow);
|
||||
SubscribeLocalEvent<CanPerformComboComponent, JudoEyePokePerformedEvent>(OnJudoEyepoke);
|
||||
SubscribeLocalEvent<CanPerformComboComponent, JudoArmbarPerformedEvent>(OnJudoArmbar);
|
||||
|
||||
SubscribeLocalEvent<GrantCorporateJudoComponent, ClothingGotEquippedEvent>(OnGrantCorporateJudo);
|
||||
SubscribeLocalEvent<GrantCorporateJudoComponent, ClothingGotUnequippedEvent>(OnRemoveCorporateJudo);
|
||||
//SubscribeLocalEvent<CanPerformComboComponent, JudoGoldenBlastPerformedEvent>(OnJudoGoldenBlast); -- rework
|
||||
// Wheel throw
|
||||
// Discombobulate
|
||||
}
|
||||
|
||||
#region Generic Methods
|
||||
|
||||
private void OnGrantCorporateJudo(Entity<GrantCorporateJudoComponent> ent, ref ClothingGotEquippedEvent args)
|
||||
{
|
||||
if (!_netManager.IsServer)
|
||||
return;
|
||||
|
||||
var user = args.Wearer;
|
||||
TryGrant(ent.Comp, user);
|
||||
}
|
||||
|
||||
private void OnRemoveCorporateJudo(Entity<GrantCorporateJudoComponent> ent, ref ClothingGotUnequippedEvent args)
|
||||
{
|
||||
var user = args.Wearer;
|
||||
if (!TryComp<MartialArtsKnowledgeComponent>(user, out var martialArtsKnowledge))
|
||||
return;
|
||||
|
||||
if (martialArtsKnowledge.MartialArtsForm != MartialArtsForms.CorporateJudo)
|
||||
return;
|
||||
|
||||
RemComp<MartialArtsKnowledgeComponent>(user);
|
||||
RemComp<CanPerformComboComponent>(user);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Combo Methods
|
||||
|
||||
private void OnJudoThrow(Entity<CanPerformComboComponent> 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<PullableComponent>(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<CanPerformComboComponent> 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<TemporaryBlindnessComponent>(target,
|
||||
"TemporaryBlindness",
|
||||
TimeSpan.FromSeconds(2),
|
||||
true,
|
||||
status);
|
||||
_status.TryAddStatusEffect<BlurryVisionComponent>(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<CanPerformComboComponent> 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<CanPerformComboComponent> 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<PullableComponent>(target, out var pullable))
|
||||
_pulling.TryStopPull(target, pullable, ent, true);
|
||||
_audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/genhit3.ogg"), target);
|
||||
}
|
||||
*/
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// This handles...
|
||||
/// </summary>
|
||||
public abstract partial class SharedMartialArtsSystem
|
||||
{
|
||||
private void InitializeKravMaga()
|
||||
{
|
||||
SubscribeLocalEvent<KravMagaComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<KravMagaComponent, KravMagaActionEvent>(OnKravMagaAction);
|
||||
SubscribeLocalEvent<KravMagaComponent, MeleeHitEvent>(OnMeleeHitEvent);
|
||||
SubscribeLocalEvent<KravMagaComponent, ComponentShutdown>(OnKravMagaShutdown);
|
||||
}
|
||||
|
||||
private void OnMeleeHitEvent(Entity<KravMagaComponent> ent, ref MeleeHitEvent args)
|
||||
{
|
||||
if (args.HitEntities.Count <= 0)
|
||||
return;
|
||||
|
||||
foreach (var hitEntity in args.HitEntities)
|
||||
{
|
||||
if (!HasComp<MobStateComponent>(hitEntity))
|
||||
continue;
|
||||
if (!TryComp<RequireProjectileTargetComponent>(hitEntity, out var isDowned))
|
||||
continue;
|
||||
|
||||
DoKravMaga(ent, hitEntity, isDowned);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoKravMaga(Entity<KravMagaComponent> 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<KravMagaSilencedComponent>(hitEntity);
|
||||
comp.SilencedTime = _timing.CurTime + TimeSpan.FromSeconds(moveComp.EffectTime);
|
||||
break;
|
||||
case KravMagaMoves.LungPunch:
|
||||
_stamina.TakeStaminaDamage(hitEntity, moveComp.StaminaDamage);
|
||||
var blockedBreathingComponent = EnsureComp<KravMagaBlockedBreathingComponent>(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<KravMagaComponent> ent, ref KravMagaActionEvent args)
|
||||
{
|
||||
var actionEnt = args.Action.Owner;
|
||||
if (!TryComp<KravMagaActionComponent>(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<KravMagaComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
if (HasComp<MartialArtsKnowledgeComponent>(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<KravMagaComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (!TryComp<KravMagaComponent>(ent, out var kravMaga))
|
||||
return;
|
||||
|
||||
foreach (var action in ent.Comp.KravMagaMoveEntities)
|
||||
{
|
||||
_actions.RemoveAction(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<CanPerformComboComponent, SleepingCarpGnashingTeethPerformedEvent>(OnSleepingCarpGnashing);
|
||||
SubscribeLocalEvent<CanPerformComboComponent, SleepingCarpKneeHaulPerformedEvent>(OnSleepingCarpKneeHaul);
|
||||
SubscribeLocalEvent<CanPerformComboComponent, SleepingCarpCrashingWavesPerformedEvent>(OnSleepingCarpCrashingWaves);
|
||||
|
||||
SubscribeLocalEvent<GrantSleepingCarpComponent, UseInHandEvent>(OnGrantSleepingCarp);
|
||||
}
|
||||
|
||||
#region Generic Methods
|
||||
|
||||
private void OnGrantSleepingCarp(Entity<GrantSleepingCarpComponent> 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<ReflectComponent>(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<GrantSleepingCarpComponent> 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<CanPerformComboComponent> ent,
|
||||
ref SleepingCarpGnashingTeethPerformedEvent args)
|
||||
{
|
||||
if (!_proto.TryIndex(ent.Comp.BeingPerformed, out var proto)
|
||||
|| !TryUseMartialArt(ent, proto.MartialArtsForm, out var target, out _))
|
||||
return;
|
||||
|
||||
if (!TryComp<MartialArtsKnowledgeComponent>(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<RequireProjectileTargetComponent>(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<CanPerformComboComponent> 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<PullableComponent>(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<CanPerformComboComponent> 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<PullableComponent>(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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Handles most of Martial Arts Systems.
|
||||
/// </summary>
|
||||
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<MartialArtsKnowledgeComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<MartialArtsKnowledgeComponent, CheckGrabOverridesEvent>(CheckGrabStageOverride);
|
||||
SubscribeLocalEvent<MartialArtsKnowledgeComponent, MeleeHitEvent>(OnMeleeHit);
|
||||
SubscribeLocalEvent<MartialArtsKnowledgeComponent, ShotAttemptedEvent>(OnShotAttempt);
|
||||
SubscribeLocalEvent<KravMagaSilencedComponent, SpeakAttemptEvent>(OnSilencedSpeakAttempt);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<CanPerformComboComponent>();
|
||||
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<KravMagaSilencedComponent>();
|
||||
while (kravSilencedQuery.MoveNext(out var ent, out var comp))
|
||||
{
|
||||
if (_timing.CurTime < comp.SilencedTime)
|
||||
continue;
|
||||
RemComp<KravMagaSilencedComponent>(ent);
|
||||
}
|
||||
|
||||
var kravBlockedQuery = EntityQueryEnumerator<KravMagaBlockedBreathingComponent>();
|
||||
while (kravBlockedQuery.MoveNext(out var ent, out var comp))
|
||||
{
|
||||
if (_timing.CurTime < comp.BlockedTime)
|
||||
continue;
|
||||
RemComp<KravMagaBlockedBreathingComponent>(ent);
|
||||
}
|
||||
}
|
||||
|
||||
#region Event Methods
|
||||
|
||||
private void OnMeleeHit(Entity<MartialArtsKnowledgeComponent> 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<MartialArtsKnowledgeComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if(TryComp<CanPerformComboComponent>(ent, out var comboComponent))
|
||||
comboComponent.AllowedCombos.Clear();
|
||||
}
|
||||
|
||||
private void CheckGrabStageOverride<T>(EntityUid uid, T component, CheckGrabOverridesEvent args)
|
||||
where T : GrabStagesOverrideComponent
|
||||
{
|
||||
if (args.Stage == GrabStage.Soft)
|
||||
args.Stage = component.StartingStage;
|
||||
}
|
||||
|
||||
private void OnSilencedSpeakAttempt(Entity<KravMagaSilencedComponent> 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<MartialArtsKnowledgeComponent> 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<KravMagaComponent>(user))
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("cqc-fail-knowanother"), user, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HasComp<CanPerformComboComponent>(user))
|
||||
{
|
||||
var canPerformComboComponent = EnsureComp<CanPerformComboComponent>(user);
|
||||
var martialArtsKnowledgeComponent = EnsureComp<MartialArtsKnowledgeComponent>(user);
|
||||
LoadPrototype(user, martialArtsKnowledgeComponent, comp.MartialArtsForm);
|
||||
martialArtsKnowledgeComponent.Blocked = false;
|
||||
if (TryComp<MeleeWeaponComponent>(user, out var meleeWeaponComponent))
|
||||
{
|
||||
var newDamage = new DamageSpecifier();
|
||||
newDamage.DamageDict.Add("Blunt", martialArtsKnowledgeComponent.BaseDamageModifier);
|
||||
meleeWeaponComponent.Damage += newDamage;
|
||||
}
|
||||
Dirty(user, canPerformComboComponent);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!TryComp<MartialArtsKnowledgeComponent>(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<ComboListPrototype> 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<CanPerformComboComponent>(uid);
|
||||
if (!_proto.TryIndex<MartialArtPrototype>(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<CanPerformComboComponent> ent,
|
||||
MartialArtsForms form,
|
||||
out EntityUid target,
|
||||
out bool downed)
|
||||
{
|
||||
target = EntityUid.Invalid;
|
||||
downed = false;
|
||||
|
||||
if (ent.Comp.CurrentTarget == null)
|
||||
return false;
|
||||
|
||||
if (!TryComp<MartialArtsKnowledgeComponent>(ent, out var knowledgeComponent))
|
||||
return false;
|
||||
|
||||
if (!TryComp<RequireProjectileTargetComponent>(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<TargetingComponent>(ent, out var targetingComponent))
|
||||
return;
|
||||
damage.DamageDict.Add(damageType, damageAmount);
|
||||
_damageable.TryChangeDamage(target, damage, origin: ent, targetPart: targetBodyPart ?? targetingComponent.Target);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
16
Content.Shared/_Goobstation/TableSlam/PostTabledComponent.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._Goobstation.TableSlam;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for...
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class PostTabledComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public TimeSpan PostTabledShovableTime = TimeSpan.Zero;
|
||||
|
||||
[DataField]
|
||||
public float ParalyzeChance = 0.35f;
|
||||
}
|
||||
157
Content.Shared/_Goobstation/TableSlam/TableSlamSystem.cs
Normal file
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// This handles...
|
||||
/// </summary>
|
||||
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!;
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<PullerComponent, MeleeHitEvent>(OnMeleeHit);
|
||||
SubscribeLocalEvent<TableableComponent, StartCollideEvent>(OnStartCollide);
|
||||
SubscribeLocalEvent<PostTabledComponent, DisarmAttemptEvent>(OnDisarmAttemptEvent);
|
||||
}
|
||||
|
||||
private void OnDisarmAttemptEvent(Entity<PostTabledComponent> ent, ref DisarmAttemptEvent args)
|
||||
{
|
||||
if(!_random.Prob(ent.Comp.ParalyzeChance))
|
||||
return;
|
||||
|
||||
_stunSystem.TryParalyze(ent, TimeSpan.FromSeconds(3), false);
|
||||
RemComp<PostTabledComponent>(ent);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
var tabledQuery = EntityQueryEnumerator<PostTabledComponent>();
|
||||
while (tabledQuery.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
if (_gameTiming.CurTime >= comp.PostTabledShovableTime)
|
||||
RemComp<PostTabledComponent>(uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMeleeHit(Entity<PullerComponent> ent, ref MeleeHitEvent args)
|
||||
{
|
||||
if (ent.Comp.GrabStage < GrabStage.Suffocate
|
||||
|| ent.Comp.Pulling == null)
|
||||
return;
|
||||
|
||||
if(!TryComp<PullableComponent>(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<BonkableComponent>(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<PullableComponent> ent, Entity<PullerComponent> 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<TableableComponent>(ent, out var tableableComp)) // Checks that the entity being tabled has the TableableComponent
|
||||
{
|
||||
tableableComp.BeingTabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
tableableComp = EnsureComp<TableableComponent>(ent); // Adds the Tableable Component if it doesn't exist
|
||||
tableableComp.BeingTabled = true; // This shit is so code :skull:
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStartCollide(Entity<TableableComponent> ent, ref StartCollideEvent args)
|
||||
{
|
||||
if(!ent.Comp.BeingTabled)
|
||||
return;
|
||||
|
||||
if (!HasComp<BonkableComponent>(args.OtherEntity))
|
||||
return;
|
||||
|
||||
var modifierOnGlassBreak = 1;
|
||||
if (TryComp<GlassTableComponent>(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<string, FixedPoint2> { { "Blunt", ent.Comp.TabledDamage } },
|
||||
},
|
||||
targetPart: TargetBodyPart.Torso);
|
||||
_damageableSystem.TryChangeDamage(ent,
|
||||
new DamageSpecifier()
|
||||
{
|
||||
DamageDict = new Dictionary<string, FixedPoint2> { { "Blunt", ent.Comp.TabledDamage } },
|
||||
});
|
||||
}
|
||||
|
||||
_staminaSystem.TakeStaminaDamage(ent, ent.Comp.TabledStaminaDamage);
|
||||
_stunSystem.TryKnockdown(ent, TimeSpan.FromSeconds(3 * modifierOnGlassBreak), false);
|
||||
var postTabledComponent = EnsureComp<PostTabledComponent>(ent);
|
||||
postTabledComponent.PostTabledShovableTime = _gameTiming.CurTime.Add(TimeSpan.FromSeconds(3));
|
||||
ent.Comp.BeingTabled = false;
|
||||
|
||||
//_audioSystem.PlayPvs("/Audio/Effects/thudswoosh.ogg", uid);
|
||||
}
|
||||
}
|
||||
32
Content.Shared/_Goobstation/TableSlam/TableableComponent.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._Goobstation.TableSlam;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class TableableComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// If this pullable being tabled.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool BeingTabled = false;
|
||||
|
||||
/// <summary>
|
||||
/// Constant for tabling throw math
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float BasedTabledForceSpeed = 5f;
|
||||
|
||||
/// <summary>
|
||||
/// Stamina damage. taken on tabled
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float TabledStaminaDamage = 40f;
|
||||
|
||||
/// <summary>
|
||||
/// Damage taken on being tabled.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float TabledDamage = 5f;
|
||||
// Goobstation end
|
||||
}
|
||||
@@ -8,8 +8,6 @@ public sealed partial class GrabThrownComponent : Component
|
||||
{
|
||||
public DamageSpecifier? DamageOnCollide;
|
||||
|
||||
public DamageSpecifier? WallDamageOnCollide;
|
||||
|
||||
public float? StaminaDamageOnCollide;
|
||||
|
||||
public List<EntityUid> IgnoreEntity = new();
|
||||
|
||||
@@ -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<ThrownItemComponent>(ent.Owner))
|
||||
if (!HasComp<ThrownItemComponent>(ent))
|
||||
{
|
||||
RemComp<GrabThrownComponent>(ent.Owner);
|
||||
RemComp<GrabThrownComponent>(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent.Comp.IgnoreEntity.Contains(args.OtherEntity))
|
||||
return;
|
||||
|
||||
if (!HasComp<DamageableComponent>(ent.Owner))
|
||||
RemComp<GrabThrownComponent>(ent.Owner);
|
||||
if (!HasComp<DamageableComponent>(ent))
|
||||
RemComp<GrabThrownComponent>(ent);
|
||||
|
||||
if(!TryComp<PhysicsComponent>(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<EntityUid>() { ent.Owner }, Filter.Pvs(ent.Owner, entityManager: EntityManager));
|
||||
_color.RaiseEffect(Color.Red, new List<EntityUid>() { ent }, Filter.Pvs(ent, entityManager: EntityManager));
|
||||
}
|
||||
|
||||
private void OnStopThrow(EntityUid uid, GrabThrownComponent comp, StopThrowEvent args)
|
||||
@@ -77,26 +84,23 @@ public sealed class GrabThrownSystem : EntitySystem
|
||||
/// <param name="uid">Entity to throw</param>
|
||||
/// <param name="thrower">Entity that throws</param>
|
||||
/// <param name="vector">Direction</param>
|
||||
/// <param name="grabThrownSpeed">How fast you fly when thrown</param>
|
||||
/// <param name="staminaDamage">Stamina damage on collide</param>
|
||||
/// <param name="damageToUid">Damage to entity on collide</param>
|
||||
/// <param name="damageToWall">Damage to wall or anything that was hit by entity</param>
|
||||
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<GrabThrownComponent>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -1 +0,0 @@
|
||||
steal-target-power-gloves = power gloves
|
||||
@@ -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!
|
||||
@@ -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.
|
||||
@@ -1,3 +0,0 @@
|
||||
ent-ClothingHandsGlovesPowergloveReal = силовые перчатки
|
||||
.desc = Помни основы CQC.
|
||||
.suffix = { "Смотритель" }
|
||||
@@ -1 +0,0 @@
|
||||
steal-target-power-gloves = силовые перчатки
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
weights:
|
||||
CaptainIDStealObjective: 1
|
||||
CMOHyposprayStealObjective: 1
|
||||
PowerGlovesStealObjective: 1 # WWDP warden's CQC gloves
|
||||
CMOCrewMonitorStealObjective: 1
|
||||
RDHardsuitStealObjective: 1
|
||||
NukeDiskStealObjective: 1
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
14
Resources/Prototypes/_EE/Tags/tags.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
- type: Tag
|
||||
id: DockCargoShuttle
|
||||
|
||||
- type: Tag
|
||||
id: DockDart
|
||||
|
||||
- type: Tag
|
||||
id: DockInfiltrator
|
||||
|
||||
- type: Tag
|
||||
id: DockPathfinder
|
||||
|
||||
- type: Tag
|
||||
id: DockSANDropship
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
15
Resources/Prototypes/_Goobstation/Entities/Specific/bso.yml
Normal file
@@ -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
|
||||
@@ -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
|
||||
64
Resources/Prototypes/_Goobstation/MartialArts/carp.yml
Normal file
@@ -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
|
||||
|
||||
69
Resources/Prototypes/_Goobstation/MartialArts/cqc.yml
Normal file
@@ -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
|
||||
45
Resources/Prototypes/_Goobstation/MartialArts/judo.yml
Normal file
@@ -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
|
||||
50
Resources/Prototypes/_Goobstation/MartialArts/kravmaga.yml
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
- type: stealTargetGroup
|
||||
id: WardenPowerGloves
|
||||
name: steal-target-power-gloves
|
||||
sprite:
|
||||
sprite: Clothing/Hands/Gloves/powerglove.rsi
|
||||
state: icon
|
||||
@@ -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
|
||||
@@ -23,4 +23,4 @@
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 552 B |
|
After Width: | Height: | Size: 639 B |
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 615 B |
|
After Width: | Height: | Size: 503 B |
|
After Width: | Height: | Size: 518 B |
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 530 B |
|
After Width: | Height: | Size: 486 B |
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 327 B |
|
After Width: | Height: | Size: 225 B |
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 409 B |
|
After Width: | Height: | Size: 308 B |
|
After Width: | Height: | Size: 295 B |
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 633 B |
|
After Width: | Height: | Size: 673 B |