diff --git a/Content.Server/Climbing/ClimbSystem.cs b/Content.Server/Climbing/ClimbSystem.cs index d41f94d45c..c43e26b4a9 100644 --- a/Content.Server/Climbing/ClimbSystem.cs +++ b/Content.Server/Climbing/ClimbSystem.cs @@ -1,11 +1,14 @@ using Content.Server.Climbing.Components; using Content.Server.DoAfter; +using Content.Server.Interaction.Components; using Content.Server.Popups; using Content.Server.Stunnable; +using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; using Content.Shared.ActionBlocker; using Content.Shared.Body.Components; using Content.Shared.Body.Part; using Content.Shared.Buckle.Components; +using Content.Shared.CCVar; using Content.Shared.Climbing; using Content.Shared.Damage; using Content.Shared.DragDrop; @@ -16,17 +19,21 @@ using Content.Shared.Physics; using Content.Shared.Popups; using Content.Shared.Verbs; using JetBrains.Annotations; +using Robust.Server.GameObjects; +using Robust.Shared.Configuration; using Robust.Shared.GameStates; using Robust.Shared.Physics; using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Physics.Dynamics; using Robust.Shared.Player; +using SharpZstd.Interop; namespace Content.Server.Climbing; [UsedImplicitly] public sealed class ClimbSystem : SharedClimbSystem { + [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; @@ -34,6 +41,7 @@ public sealed class ClimbSystem : SharedClimbSystem [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly StunSystem _stunSystem = default!; + [Dependency] private readonly AudioSystem _audioSystem = default!; private const string ClimbingFixtureName = "climb"; private const int ClimbingCollisionGroup = (int) (CollisionGroup.TableLayer | CollisionGroup.LowImpassable); @@ -80,6 +88,9 @@ public sealed class ClimbSystem : SharedClimbSystem if (!args.CanAccess || !args.CanInteract || !_actionBlockerSystem.CanMove(args.User)) return; + if (component.Bonk && _cfg.GetCVar(CCVars.GameTableBonk)) + return; + if (!TryComp(args.User, out ClimbingComponent? climbingComponent) || climbingComponent.IsClimbing) return; @@ -102,6 +113,9 @@ public sealed class ClimbSystem : SharedClimbSystem if (!TryComp(entityToMove, out ClimbingComponent? climbingComponent) || climbingComponent.IsClimbing) return; + if (TryBonk(component, user)) + return; + _doAfterSystem.DoAfter(new DoAfterEventArgs(entityToMove, component.ClimbDelay, default, climbable) { BreakOnTargetMove = true, @@ -112,6 +126,33 @@ public sealed class ClimbSystem : SharedClimbSystem }); } + private bool TryBonk(ClimbableComponent component, EntityUid user) + { + if (!component.Bonk) + return false; + + if (!_cfg.GetCVar(CCVars.GameTableBonk)) + { + // Not set to always bonk, try clumsy roll. + if (!TryComp(user, out ClumsyComponent? clumsy)) + return false; + + if (!clumsy.RollClumsy(component.BonkClumsyChance)) + return false; + } + + // BONK! + + _audioSystem.PlayPvs(component.BonkSound, component.Owner); + + _stunSystem.TryKnockdown(user, TimeSpan.FromSeconds(component.BonkTime), true); + + if (component.BonkDamage is { } bonkDmg) + _damageableSystem.TryChangeDamage(user, bonkDmg, true); + + return true; + } + private void OnClimbFinished(EntityUid uid, ClimbingComponent climbing, ClimbFinishedEvent args) { Climb(uid, args.User, args.Climbable, climbing: climbing); diff --git a/Content.Server/Climbing/Components/ClimbableComponent.cs b/Content.Server/Climbing/Components/ClimbableComponent.cs index 67efd88c86..53cd673d5c 100644 --- a/Content.Server/Climbing/Components/ClimbableComponent.cs +++ b/Content.Server/Climbing/Components/ClimbableComponent.cs @@ -1,4 +1,7 @@ +using Content.Shared.CCVar; using Content.Shared.Climbing; +using Content.Shared.Damage; +using Robust.Shared.Audio; namespace Content.Server.Climbing.Components; @@ -12,4 +15,36 @@ public sealed class ClimbableComponent : SharedClimbableComponent [ViewVariables] [DataField("delay")] public float ClimbDelay = 0.8f; + + /// + /// If set, people can bonk on this if is set or if they are clumsy. + /// + [ViewVariables] [DataField("bonk")] public bool Bonk = false; + + /// + /// Chance of bonk triggering if the user is clumsy. + /// + [ViewVariables] [DataField("bonkClumsyChance")] + public float BonkClumsyChance = 0.75f; + + /// + /// Sound to play when bonking. + /// + /// + [ViewVariables] [DataField("bonkSound")] + public SoundSpecifier? BonkSound; + + /// + /// How long to stun players on bonk, in seconds. + /// + /// + [ViewVariables] [DataField("bonkTime")] + public float BonkTime = 2; + + /// + /// How much damage to apply on bonk. + /// + /// + [ViewVariables] [DataField("bonkDamage")] + public DamageSpecifier? BonkDamage; } diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 523f5164ba..717709c3ef 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -231,6 +231,12 @@ namespace Content.Shared.CCVar public static readonly CVarDef PanicBunkerMinAccountAge = CVarDef.Create("game.panic_bunker.min_account_age", 1440, CVar.SERVERONLY); + /// + /// Make people bonk when trying to climb certain objects like tables. + /// + public static readonly CVarDef GameTableBonk = + CVarDef.Create("game.table_bonk", false, CVar.SERVERONLY); + #if EXCEPTION_TOLERANCE /// /// Amount of times round start must fail before the server is shut down. diff --git a/Resources/Audio/Items/attributions.yml b/Resources/Audio/Items/attributions.yml new file mode 100644 index 0000000000..84c0d544d0 --- /dev/null +++ b/Resources/Audio/Items/attributions.yml @@ -0,0 +1,9 @@ +- files: ["trayhit1.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Time immemorial" + source: "https://github.com/tgstation/tgstation/blob/172b533d0257fcc1f8a05406f1c9fad514c14d88/sound/items/trayhit1.ogg" + +- files: ["trayhit2.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Time immemorial" + source: "https://github.com/tgstation/tgstation/blob/172b533d0257fcc1f8a05406f1c9fad514c14d88/sound/items/trayhit2.ogg" \ No newline at end of file diff --git a/Resources/Audio/Items/trayhit1.ogg b/Resources/Audio/Items/trayhit1.ogg new file mode 100644 index 0000000000..a2b5532a54 Binary files /dev/null and b/Resources/Audio/Items/trayhit1.ogg differ diff --git a/Resources/Audio/Items/trayhit2.ogg b/Resources/Audio/Items/trayhit2.ogg new file mode 100644 index 0000000000..066e44bf0b Binary files /dev/null and b/Resources/Audio/Items/trayhit2.ogg differ diff --git a/Resources/Prototypes/Entities/Structures/Furniture/Tables/base_structuretables.yml b/Resources/Prototypes/Entities/Structures/Furniture/Tables/base_structuretables.yml index 0a0072385d..4211265a68 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/Tables/base_structuretables.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/Tables/base_structuretables.yml @@ -27,4 +27,10 @@ key: state base: state_ - type: Climbable + bonk: true + bonkDamage: + types: + Blunt: 4 + bonkSound: !type:SoundCollectionSpecifier + collection: TrayHit - type: Clickable diff --git a/Resources/Prototypes/Entities/Structures/Furniture/Tables/tables.yml b/Resources/Prototypes/Entities/Structures/Furniture/Tables/tables.yml index abd0d2da88..051d2c9ec6 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/Tables/tables.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/Tables/tables.yml @@ -45,7 +45,7 @@ - type: Construction graph: Table node: TableFrame - + - type: entity id: CounterWoodFrame parent: BaseStructure @@ -216,6 +216,12 @@ - type: Construction graph: Table node: TableReinforced + - type: Climbable + # Reinforced tables are extra tough + bonkDamage: + types: + Blunt: 8 + bonkTime: 3 - type: entity id: TableGlass @@ -490,7 +496,7 @@ - type: Construction graph: Table node: CounterWood - + - type: entity id: TableCounterMetal parent: CounterMetalFrame diff --git a/Resources/Prototypes/SoundCollections/tray.yml b/Resources/Prototypes/SoundCollections/tray.yml new file mode 100644 index 0000000000..960b6dfe2c --- /dev/null +++ b/Resources/Prototypes/SoundCollections/tray.yml @@ -0,0 +1,5 @@ +- type: soundCollection + id: TrayHit + files: + - /Audio/Items/trayhit1.ogg + - /Audio/Items/trayhit2.ogg