Glass tables break when climbed on (#6246)
This commit is contained in:
@@ -32,6 +32,7 @@ namespace Content.Client.Entry
|
|||||||
"PoweredLight",
|
"PoweredLight",
|
||||||
"Smes",
|
"Smes",
|
||||||
"LightBulb",
|
"LightBulb",
|
||||||
|
"GlassTable",
|
||||||
"Healing",
|
"Healing",
|
||||||
"Material",
|
"Material",
|
||||||
"RandomAppearance",
|
"RandomAppearance",
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Climbing.Components;
|
using Content.Server.Climbing.Components;
|
||||||
|
using Content.Server.Popups;
|
||||||
|
using Content.Server.Stunnable;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Climbing;
|
using Content.Shared.Climbing;
|
||||||
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
namespace Content.Server.Climbing
|
namespace Content.Server.Climbing
|
||||||
{
|
{
|
||||||
@@ -18,6 +23,9 @@ namespace Content.Server.Climbing
|
|||||||
private readonly HashSet<ClimbingComponent> _activeClimbers = new();
|
private readonly HashSet<ClimbingComponent> _activeClimbers = new();
|
||||||
|
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
|
[Dependency] private readonly StunSystem _stunSystem = default!;
|
||||||
|
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||||
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -25,6 +33,7 @@ namespace Content.Server.Climbing
|
|||||||
|
|
||||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
||||||
SubscribeLocalEvent<ClimbableComponent, GetAlternativeVerbsEvent>(AddClimbVerb);
|
SubscribeLocalEvent<ClimbableComponent, GetAlternativeVerbsEvent>(AddClimbVerb);
|
||||||
|
SubscribeLocalEvent<GlassTableComponent, ClimbedOnEvent>(OnGlassClimbed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ForciblySetClimbing(EntityUid uid, ClimbingComponent? component = null)
|
public void ForciblySetClimbing(EntityUid uid, ClimbingComponent? component = null)
|
||||||
@@ -47,12 +56,24 @@ namespace Content.Server.Climbing
|
|||||||
|
|
||||||
// Add a climb verb
|
// Add a climb verb
|
||||||
Verb verb = new();
|
Verb verb = new();
|
||||||
verb.Act = () => component.TryClimb(args.User);
|
verb.Act = () => component.TryClimb(args.User, args.Target);
|
||||||
verb.Text = Loc.GetString("comp-climbable-verb-climb");
|
verb.Text = Loc.GetString("comp-climbable-verb-climb");
|
||||||
// TODO VERBS ICON add a climbing icon?
|
// TODO VERBS ICON add a climbing icon?
|
||||||
args.Verbs.Add(verb);
|
args.Verbs.Add(verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnGlassClimbed(EntityUid uid, GlassTableComponent component, ClimbedOnEvent args)
|
||||||
|
{
|
||||||
|
_damageableSystem.TryChangeDamage(args.Climber, component.ClimberDamage);
|
||||||
|
_damageableSystem.TryChangeDamage(uid, component.TableDamage);
|
||||||
|
_stunSystem.TryParalyze(args.Climber, TimeSpan.FromSeconds(component.StunTime), true);
|
||||||
|
|
||||||
|
// Not shown to the user, since they already get a 'you climb on the glass table' popup
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("glass-table-shattered-others",
|
||||||
|
("table", uid), ("climber", args.Climber)), args.Climber,
|
||||||
|
Filter.Pvs(uid).RemoveWhereAttachedEntity(puid => puid == args.Climber));
|
||||||
|
}
|
||||||
|
|
||||||
public void AddActiveClimber(ClimbingComponent climbingComponent)
|
public void AddActiveClimber(ClimbingComponent climbingComponent)
|
||||||
{
|
{
|
||||||
_activeClimbers.Add(climbingComponent);
|
_activeClimbers.Add(climbingComponent);
|
||||||
|
|||||||
@@ -139,17 +139,17 @@ namespace Content.Server.Climbing.Components
|
|||||||
{
|
{
|
||||||
if (eventArgs.User == eventArgs.Dragged)
|
if (eventArgs.User == eventArgs.Dragged)
|
||||||
{
|
{
|
||||||
TryClimb(eventArgs.User);
|
TryClimb(eventArgs.User, eventArgs.Target);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TryMoveEntity(eventArgs.User, eventArgs.Dragged);
|
TryMoveEntity(eventArgs.User, eventArgs.Dragged, eventArgs.Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void TryMoveEntity(EntityUid user, EntityUid entityToMove)
|
private async void TryMoveEntity(EntityUid user, EntityUid entityToMove, EntityUid climbable)
|
||||||
{
|
{
|
||||||
var doAfterEventArgs = new DoAfterEventArgs(user, _climbDelay, default, entityToMove)
|
var doAfterEventArgs = new DoAfterEventArgs(user, _climbDelay, default, entityToMove)
|
||||||
{
|
{
|
||||||
@@ -184,6 +184,9 @@ namespace Content.Server.Climbing.Components
|
|||||||
// we may potentially need additional logic since we're forcing a player onto a climbable
|
// we may potentially need additional logic since we're forcing a player onto a climbable
|
||||||
// there's also the cases where the user might collide with the person they are forcing onto the climbable that i haven't accounted for
|
// there's also the cases where the user might collide with the person they are forcing onto the climbable that i haven't accounted for
|
||||||
|
|
||||||
|
_entities.EventBus.RaiseLocalEvent(entityToMove, new StartClimbEvent(climbable), false);
|
||||||
|
_entities.EventBus.RaiseLocalEvent(climbable, new ClimbedOnEvent(entityToMove), false);
|
||||||
|
|
||||||
var othersMessage = Loc.GetString("comp-climbable-user-climbs-force-other",
|
var othersMessage = Loc.GetString("comp-climbable-user-climbs-force-other",
|
||||||
("user", user), ("moved-user", entityToMove), ("climbable", Owner));
|
("user", user), ("moved-user", entityToMove), ("climbable", Owner));
|
||||||
user.PopupMessageOtherClients(othersMessage);
|
user.PopupMessageOtherClients(othersMessage);
|
||||||
@@ -193,7 +196,7 @@ namespace Content.Server.Climbing.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void TryClimb(EntityUid user)
|
public async void TryClimb(EntityUid user, EntityUid climbable)
|
||||||
{
|
{
|
||||||
if (!_entities.TryGetComponent(user, out ClimbingComponent? climbingComponent) || climbingComponent.IsClimbing)
|
if (!_entities.TryGetComponent(user, out ClimbingComponent? climbingComponent) || climbingComponent.IsClimbing)
|
||||||
return;
|
return;
|
||||||
@@ -216,6 +219,9 @@ namespace Content.Server.Climbing.Components
|
|||||||
var direction = (_entities.GetComponent<TransformComponent>(Owner).WorldPosition - userPos).Normalized;
|
var direction = (_entities.GetComponent<TransformComponent>(Owner).WorldPosition - userPos).Normalized;
|
||||||
var endPoint = _entities.GetComponent<TransformComponent>(Owner).WorldPosition;
|
var endPoint = _entities.GetComponent<TransformComponent>(Owner).WorldPosition;
|
||||||
|
|
||||||
|
_entities.EventBus.RaiseLocalEvent(user, new StartClimbEvent(climbable), false);
|
||||||
|
_entities.EventBus.RaiseLocalEvent(climbable, new ClimbedOnEvent(user), false);
|
||||||
|
|
||||||
var climbMode = _entities.GetComponent<ClimbingComponent>(user);
|
var climbMode = _entities.GetComponent<ClimbingComponent>(user);
|
||||||
climbMode.IsClimbing = true;
|
climbMode.IsClimbing = true;
|
||||||
|
|
||||||
@@ -239,3 +245,29 @@ namespace Content.Server.Climbing.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on an entity when it is climbed on.
|
||||||
|
/// </summary>
|
||||||
|
public class ClimbedOnEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid Climber;
|
||||||
|
|
||||||
|
public ClimbedOnEvent(EntityUid climber)
|
||||||
|
{
|
||||||
|
Climber = climber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised on an entity when it successfully climbs on something.
|
||||||
|
/// </summary>
|
||||||
|
public class StartClimbEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid Climbable;
|
||||||
|
|
||||||
|
public StartClimbEvent(EntityUid climbable)
|
||||||
|
{
|
||||||
|
Climbable = climbable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
33
Content.Server/Climbing/Components/GlassTableComponent.cs
Normal file
33
Content.Server/Climbing/Components/GlassTableComponent.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using Content.Shared.Damage;
|
||||||
|
using Robust.Shared.Analyzers;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
|
||||||
|
namespace Content.Server.Climbing.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Glass tables shatter and stun you when climbed on.
|
||||||
|
/// This is a really entity-specific behavior, so opted to make it
|
||||||
|
/// not very generalized with regards to naming.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, Friend(typeof(ClimbSystem))]
|
||||||
|
[ComponentProtoName("GlassTable")]
|
||||||
|
public class GlassTableComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// How much damage should be given to the climber?
|
||||||
|
/// </summary>
|
||||||
|
[DataField("climberDamage")]
|
||||||
|
public DamageSpecifier ClimberDamage = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How much damage should be given to the table when climbed on?
|
||||||
|
/// </summary>
|
||||||
|
[DataField("tableDamage")]
|
||||||
|
public DamageSpecifier TableDamage = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How long should someone who climbs on this table be stunned for?
|
||||||
|
/// </summary>
|
||||||
|
public float StunTime = 5.0f;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
### Tables which take damage when a user is dragged onto them
|
||||||
|
|
||||||
|
## Showed to users other than the climber
|
||||||
|
glass-table-shattered-others = { CAPITALIZE(THE($table)) } cracks under the weight of { THE($climber) }!
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: TableFrame
|
id: TableFrame
|
||||||
parent: TableBase
|
# BaseStructure and not BaseTable, since these shouldn't be climbable/placeable.
|
||||||
|
parent: BaseStructure
|
||||||
name: table frame
|
name: table frame
|
||||||
description: Pieces of metal that make the frame of a table.
|
description: Pieces of metal that make the frame of a table.
|
||||||
components:
|
components:
|
||||||
@@ -8,9 +9,21 @@
|
|||||||
sprite: Structures/Furniture/Tables/frame.rsi
|
sprite: Structures/Furniture/Tables/frame.rsi
|
||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Structures/Furniture/Tables/frame.rsi
|
sprite: Structures/Furniture/Tables/frame.rsi
|
||||||
|
- type: Fixtures
|
||||||
|
fixtures:
|
||||||
|
- shape:
|
||||||
|
!type:PhysShapeAabb
|
||||||
|
bounds: "-0.45,-0.45,0.45,0.45"
|
||||||
|
mass: 50
|
||||||
|
mask:
|
||||||
|
- Impassable
|
||||||
|
- VaultImpassable
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
damageModifierSet: Metallic
|
damageModifierSet: Metallic
|
||||||
|
- type: IconSmooth
|
||||||
|
key: state
|
||||||
|
base: state_
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
thresholds:
|
thresholds:
|
||||||
- trigger:
|
- trigger:
|
||||||
@@ -104,6 +117,13 @@
|
|||||||
sprite: Structures/Furniture/Tables/glass.rsi
|
sprite: Structures/Furniture/Tables/glass.rsi
|
||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Structures/Furniture/Tables/glass.rsi
|
sprite: Structures/Furniture/Tables/glass.rsi
|
||||||
|
- type: GlassTable
|
||||||
|
climberDamage:
|
||||||
|
types:
|
||||||
|
Slash: 15
|
||||||
|
tableDamage:
|
||||||
|
types:
|
||||||
|
Blunt: 25
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
thresholds:
|
thresholds:
|
||||||
- trigger:
|
- trigger:
|
||||||
@@ -118,6 +138,8 @@
|
|||||||
ShardGlass:
|
ShardGlass:
|
||||||
min: 1
|
min: 1
|
||||||
max: 1
|
max: 1
|
||||||
|
- !type:ChangeConstructionNodeBehavior
|
||||||
|
node: TableFrame
|
||||||
- !type:DoActsBehavior
|
- !type:DoActsBehavior
|
||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
- type: Construction
|
- type: Construction
|
||||||
@@ -134,6 +156,13 @@
|
|||||||
sprite: Structures/Furniture/Tables/r_glass.rsi
|
sprite: Structures/Furniture/Tables/r_glass.rsi
|
||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Structures/Furniture/Tables/r_glass.rsi
|
sprite: Structures/Furniture/Tables/r_glass.rsi
|
||||||
|
- type: GlassTable
|
||||||
|
climberDamage:
|
||||||
|
types:
|
||||||
|
Slash: 25
|
||||||
|
tableDamage:
|
||||||
|
types:
|
||||||
|
Blunt: 40
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
thresholds:
|
thresholds:
|
||||||
- trigger:
|
- trigger:
|
||||||
@@ -143,6 +172,8 @@
|
|||||||
- !type:PlaySoundBehavior
|
- !type:PlaySoundBehavior
|
||||||
sound:
|
sound:
|
||||||
path: /Audio/Effects/glass_break2.ogg
|
path: /Audio/Effects/glass_break2.ogg
|
||||||
|
- !type:ChangeConstructionNodeBehavior
|
||||||
|
node: TableFrame
|
||||||
- !type:SpawnEntitiesBehavior
|
- !type:SpawnEntitiesBehavior
|
||||||
spawn:
|
spawn:
|
||||||
ShardGlass:
|
ShardGlass:
|
||||||
@@ -167,15 +198,24 @@
|
|||||||
sprite: Structures/Furniture/Tables/plasma.rsi
|
sprite: Structures/Furniture/Tables/plasma.rsi
|
||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Structures/Furniture/Tables/plasma.rsi
|
sprite: Structures/Furniture/Tables/plasma.rsi
|
||||||
|
- type: GlassTable
|
||||||
|
climberDamage:
|
||||||
|
types:
|
||||||
|
Slash: 30
|
||||||
|
tableDamage:
|
||||||
|
types:
|
||||||
|
Blunt: 100
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
thresholds:
|
thresholds:
|
||||||
- trigger:
|
- trigger:
|
||||||
!type:DamageTrigger
|
!type:DamageTrigger
|
||||||
damage: 20
|
damage: 50
|
||||||
behaviors:
|
behaviors:
|
||||||
- !type:PlaySoundBehavior
|
- !type:PlaySoundBehavior
|
||||||
sound:
|
sound:
|
||||||
path: /Audio/Effects/glass_break2.ogg
|
path: /Audio/Effects/glass_break2.ogg
|
||||||
|
- !type:ChangeConstructionNodeBehavior
|
||||||
|
node: TableFrame
|
||||||
- !type:SpawnEntitiesBehavior
|
- !type:SpawnEntitiesBehavior
|
||||||
spawn:
|
spawn:
|
||||||
ShardGlassPlasma:
|
ShardGlassPlasma:
|
||||||
|
|||||||
Reference in New Issue
Block a user