@@ -359,6 +359,8 @@ namespace Content.Client.Entry
|
||||
"Thirst",
|
||||
"CanEscapeInventory",
|
||||
"PowerSink",
|
||||
"Mousetrap",
|
||||
"DamageOnTrigger",
|
||||
"Wires",
|
||||
};
|
||||
}
|
||||
|
||||
12
Content.Server/Damage/Components/DamageOnTriggerComponent.cs
Normal file
12
Content.Server/Damage/Components/DamageOnTriggerComponent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Content.Shared.Damage;
|
||||
|
||||
namespace Content.Server.Damage.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class DamageOnTriggerComponent : Component
|
||||
{
|
||||
[DataField("ignoreResistances")] public bool IgnoreResistances;
|
||||
|
||||
[DataField("damage", required: true)]
|
||||
public DamageSpecifier Damage = default!;
|
||||
}
|
||||
49
Content.Server/Damage/Systems/DamageOnTriggerSystem.cs
Normal file
49
Content.Server/Damage/Systems/DamageOnTriggerSystem.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Content.Server.Damage.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.StepTrigger;
|
||||
|
||||
namespace Content.Server.Damage.Systems;
|
||||
|
||||
// System for damage that occurs on specific triggers.
|
||||
// This is originally meant for mousetraps, but could
|
||||
// probably be extended to fit other triggers as well.
|
||||
public sealed class DamageOnTriggerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<DamageOnTriggerComponent, StepTriggeredEvent>(OnStepTrigger);
|
||||
}
|
||||
|
||||
private void OnStepTrigger(EntityUid uid, DamageOnTriggerComponent component, ref StepTriggeredEvent args)
|
||||
{
|
||||
OnDamageTrigger(uid, args.Tripper, component);
|
||||
}
|
||||
|
||||
private void OnDamageTrigger(EntityUid source, EntityUid target, DamageOnTriggerComponent? component = null)
|
||||
{
|
||||
if (!Resolve(source, ref component))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var damage = new DamageSpecifier(component.Damage);
|
||||
var ev = new BeforeDamageOnTriggerEvent(damage, target);
|
||||
RaiseLocalEvent(source, ev);
|
||||
|
||||
_damageableSystem.TryChangeDamage(target, ev.Damage, component.IgnoreResistances);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BeforeDamageOnTriggerEvent : EntityEventArgs
|
||||
{
|
||||
public DamageSpecifier Damage { get; set; }
|
||||
public EntityUid Tripper { get; }
|
||||
|
||||
public BeforeDamageOnTriggerEvent(DamageSpecifier damage, EntityUid target)
|
||||
{
|
||||
Damage = damage;
|
||||
Tripper = target;
|
||||
}
|
||||
}
|
||||
21
Content.Server/Mousetrap/MousetrapComponent.cs
Normal file
21
Content.Server/Mousetrap/MousetrapComponent.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace Content.Server.Mousetrap;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class MousetrapComponent : Component
|
||||
{
|
||||
[ViewVariables]
|
||||
public bool IsActive;
|
||||
|
||||
/// <summary>
|
||||
/// Set this to change where the
|
||||
/// inflection point in the scaling
|
||||
/// equation will occur.
|
||||
/// The default is 10.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("massBalance")]
|
||||
public int MassBalance = 10;
|
||||
|
||||
[DataField("ignoreDamageIfInventorySlotsFilled")]
|
||||
public List<string> IgnoreDamageIfSlotFilled = new();
|
||||
}
|
||||
82
Content.Server/Mousetrap/MousetrapSystem.cs
Normal file
82
Content.Server/Mousetrap/MousetrapSystem.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using Content.Server.Damage.Systems;
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Mousetrap;
|
||||
using Content.Shared.StepTrigger;
|
||||
|
||||
namespace Content.Server.Mousetrap;
|
||||
|
||||
public sealed class MousetrapSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly TriggerSystem _triggerSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<MousetrapComponent, UseInHandEvent>(OnUseInHand);
|
||||
SubscribeLocalEvent<MousetrapComponent, BeforeDamageOnTriggerEvent>(BeforeDamageOnTrigger);
|
||||
SubscribeLocalEvent<MousetrapComponent, StepTriggerAttemptEvent>(OnStepTriggerAttempt);
|
||||
SubscribeLocalEvent<MousetrapComponent, StepTriggeredEvent>(OnStepTrigger);
|
||||
}
|
||||
|
||||
private void OnUseInHand(EntityUid uid, MousetrapComponent component, UseInHandEvent args)
|
||||
{
|
||||
component.IsActive = !component.IsActive;
|
||||
|
||||
UpdateVisuals(uid);
|
||||
}
|
||||
|
||||
private void OnStepTriggerAttempt(EntityUid uid, MousetrapComponent component, ref StepTriggerAttemptEvent args)
|
||||
{
|
||||
args.Continue = component.IsActive;
|
||||
}
|
||||
|
||||
private void BeforeDamageOnTrigger(EntityUid uid, MousetrapComponent component, BeforeDamageOnTriggerEvent args)
|
||||
{
|
||||
foreach (var slot in component.IgnoreDamageIfSlotFilled)
|
||||
{
|
||||
if (!_inventorySystem.TryGetSlotContainer(args.Tripper, slot, out var container, out _))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// This also means that wearing slippers won't
|
||||
// hurt the entity.
|
||||
if (container.ContainedEntity != null)
|
||||
{
|
||||
args.Damage *= 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (TryComp(args.Tripper, out PhysicsComponent? physics))
|
||||
{
|
||||
// The idea here is inverse,
|
||||
// Small - big damage,
|
||||
// Large - small damage
|
||||
// yes i punched numbers into a calculator until the graph looked right
|
||||
var scaledDamage = -50 * Math.Atan(physics.Mass - component.MassBalance) + (25 * Math.PI);
|
||||
args.Damage *= scaledDamage;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStepTrigger(EntityUid uid, MousetrapComponent component, ref StepTriggeredEvent args)
|
||||
{
|
||||
component.IsActive = false;
|
||||
_triggerSystem.Trigger(uid);
|
||||
|
||||
UpdateVisuals(uid);
|
||||
}
|
||||
|
||||
private void UpdateVisuals(EntityUid uid, MousetrapComponent? mousetrap = null, AppearanceComponent? appearance = null)
|
||||
{
|
||||
if (!Resolve(uid, ref mousetrap, ref appearance, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
appearance.SetData(MousetrapVisuals.Visual,
|
||||
mousetrap.IsActive ? MousetrapVisuals.Armed : MousetrapVisuals.Unarmed);
|
||||
}
|
||||
}
|
||||
11
Content.Shared/Mousetrap/MousetrapVisuals.cs
Normal file
11
Content.Shared/Mousetrap/MousetrapVisuals.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Mousetrap;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum MousetrapVisuals : byte
|
||||
{
|
||||
Visual,
|
||||
Armed,
|
||||
Unarmed
|
||||
}
|
||||
@@ -22,6 +22,18 @@
|
||||
category: Service
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
name: "mousetraps crate"
|
||||
id: MousetrapBoxes
|
||||
description: "Mousetraps, for when all of service is being haunted by an entire horde of rats. Use sparingly... or not."
|
||||
icon:
|
||||
sprite: Objects/Devices/mousetrap.rsi
|
||||
state: normal
|
||||
product: CrateMousetrapBoxes
|
||||
cost: 1000
|
||||
category: Service
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
name: "lung cancer crate"
|
||||
id: ServiceSmokeables
|
||||
|
||||
@@ -7,6 +7,21 @@
|
||||
- type: Sprite
|
||||
state: box
|
||||
|
||||
- type: entity
|
||||
name: mousetrap box
|
||||
parent: BoxCardboard
|
||||
id: BoxMousetrap
|
||||
description: This box is filled with mousetraps. Try not to get your hand stuck in one.
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: Mousetrap
|
||||
amount: 6
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: box
|
||||
- state: mousetraps
|
||||
|
||||
- type: entity
|
||||
name: lightbulb box
|
||||
parent: BoxCardboard
|
||||
|
||||
@@ -34,6 +34,17 @@
|
||||
- id: BoxLightbulb
|
||||
amount: 1
|
||||
|
||||
- type: entity
|
||||
id: CrateMousetrapBoxes
|
||||
name: mousetraps crate
|
||||
description: Mousetraps, for when all of service is being haunted by an entire horde of rats. Use sparingly... or not.
|
||||
parent: CrateGenericSteel
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: BoxMousetrap
|
||||
amount: 1
|
||||
|
||||
- type: entity
|
||||
id: CrateServiceSmokeables
|
||||
name: smokeables crate
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
contents:
|
||||
- id: CrowbarRed
|
||||
- id: MonkeyCubeBox
|
||||
- id: BoxMousetrap
|
||||
amount: 2
|
||||
- id: SprayBottleWater
|
||||
- id: ReagentContainerFlour
|
||||
amount: 2
|
||||
@@ -49,6 +51,8 @@
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: MopItem
|
||||
- id: BoxMousetrap
|
||||
amount: 2
|
||||
- id: WetFloorSign
|
||||
amount: 3
|
||||
- id: TrashBag
|
||||
|
||||
@@ -507,7 +507,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.48
|
||||
mass: 20
|
||||
mass: 60
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
@@ -997,7 +997,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.25
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
@@ -1213,7 +1213,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
@@ -1269,7 +1269,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
@@ -1325,7 +1325,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
@@ -225,7 +225,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
@@ -375,7 +375,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
@@ -418,7 +418,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
@@ -472,7 +472,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
@@ -515,7 +515,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
@@ -592,7 +592,7 @@
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mass: 20
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
|
||||
58
Resources/Prototypes/Entities/Objects/Devices/mousetrap.yml
Normal file
58
Resources/Prototypes/Entities/Objects/Devices/mousetrap.yml
Normal file
@@ -0,0 +1,58 @@
|
||||
- type: entity
|
||||
name: mousetrap
|
||||
parent: BaseItem
|
||||
id: Mousetrap
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Devices/mousetrap.rsi
|
||||
netsync: false
|
||||
drawdepth: SmallMobs # if mice can hide under tables, so can mousetraps
|
||||
layers:
|
||||
- state: mousetrap
|
||||
- type: StepTrigger
|
||||
intersectRatio: 0.2
|
||||
requiredTriggeredSpeed: 0
|
||||
- type: Mousetrap
|
||||
ignoreDamageIfInventorySlotsFilled:
|
||||
- shoes # shoes
|
||||
- type: DamageOnTrigger
|
||||
damage:
|
||||
types:
|
||||
Blunt: 2 # base damage, scales based on mass
|
||||
- type: EmitSoundOnUse
|
||||
sound: "/Audio/Items/Handcuffs/cuff_end.ogg"
|
||||
- type: EmitSoundOnTrigger
|
||||
sound: "/Audio/Items/snap.ogg"
|
||||
- type: Item
|
||||
sprite: Objects/Devices/mousetrap.rsi
|
||||
- type: Appearance
|
||||
visuals:
|
||||
- type: GenericEnumVisualizer
|
||||
key: enum.MousetrapVisuals.Visual
|
||||
layer: 0
|
||||
states:
|
||||
enum.MousetrapVisuals.Armed: mousetraparmed
|
||||
enum.MousetrapVisuals.Unarmed: mousetrap
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
- type: CollisionWake
|
||||
enabled: false
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
- shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.2,-0.2,0.2,0.2"
|
||||
id: "slips"
|
||||
hard: false
|
||||
layer:
|
||||
- LowImpassable
|
||||
- shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.2,-0.2,0.2,0.2"
|
||||
mass: 5
|
||||
mask:
|
||||
- ItemMask
|
||||
- type: Rotatable
|
||||
- type: Tag
|
||||
tags:
|
||||
- DroneUsable
|
||||
23
Resources/Textures/Objects/Devices/mousetrap.rsi/meta.json
Normal file
23
Resources/Textures/Objects/Devices/mousetrap.rsi/meta.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"version": 1,
|
||||
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from https://github.com/tgstation/tgstation/commit/4323540b6bec3ae93bbf13d685c2dbe0cb40a36e",
|
||||
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
|
||||
"states": [
|
||||
{
|
||||
"name": "mousetrap",
|
||||
"directions": 4
|
||||
},
|
||||
|
||||
{
|
||||
"name": "mousetraparmed",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/Objects/Devices/mousetrap.rsi/mousetrap.png
Normal file
BIN
Resources/Textures/Objects/Devices/mousetrap.rsi/mousetrap.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Reference in New Issue
Block a user