Adds slippery items (#1321)
* Start work on Slippery Component * Slips work * Add banana peel * Add required slip speed * Add slip sound * Adds soap * Make soapnt, soapsyndie and soapdeluxe inherit soap * Adds homemade soap and omega soap * Fix slipping not taking into account the entity being in a container
@@ -0,0 +1,115 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Timers;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.Throw;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Physics;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Timer = Robust.Shared.Timers.Timer;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Movement
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class SlipperyComponent : Component, ICollideBehavior
|
||||
{
|
||||
[Dependency] private IEntityManager _entityManager = default!;
|
||||
|
||||
public override string Name => "Slippery";
|
||||
|
||||
private List<EntityUid> _slipped = new List<EntityUid>();
|
||||
|
||||
/// <summary>
|
||||
/// How many seconds the mob will be paralyzed for.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float ParalyzeTime { get; set; } = 3f;
|
||||
|
||||
/// <summary>
|
||||
/// Percentage of shape intersection for a slip to occur.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float IntersectPercentage { get; set; } = 0.3f;
|
||||
|
||||
/// <summary>
|
||||
/// Entities will only be slipped if their speed exceeds this limit.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float RequiredSlipSpeed { get; set; } = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Path to the sound to be played when a mob slips.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public string SlipSound { get; set; } = "/Audio/Effects/slip.ogg";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
var collidable = Owner.GetComponent<ICollidableComponent>();
|
||||
|
||||
collidable.Hard = false;
|
||||
var shape = collidable.PhysicsShapes[0];
|
||||
shape.CollisionLayer |= (int) CollisionGroup.MobImpassable;
|
||||
shape.CollisionMask = (int)CollisionGroup.None;
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
serializer.DataField(this, x => ParalyzeTime, "paralyzeTime", 3f);
|
||||
serializer.DataField(this, x => IntersectPercentage, "intersectPercentage", 0.3f);
|
||||
serializer.DataField(this, x => RequiredSlipSpeed, "requiredSlipSpeed", 0f);
|
||||
serializer.DataField(this, x => SlipSound, "slipSound", "/Audio/Effects/slip.ogg");
|
||||
}
|
||||
|
||||
public void CollideWith(IEntity collidedWith)
|
||||
{
|
||||
if (ContainerHelpers.IsInContainer(Owner)
|
||||
|| _slipped.Contains(collidedWith.Uid)
|
||||
|| !collidedWith.TryGetComponent(out StunnableComponent stun)
|
||||
|| !collidedWith.TryGetComponent(out ICollidableComponent otherBody)
|
||||
|| !collidedWith.TryGetComponent(out PhysicsComponent otherPhysics)
|
||||
|| !Owner.TryGetComponent(out ICollidableComponent body))
|
||||
return;
|
||||
|
||||
if (otherPhysics.LinearVelocity.Length < RequiredSlipSpeed || stun.KnockedDown)
|
||||
return;
|
||||
|
||||
var percentage = otherBody.WorldAABB.IntersectPercentage(body.WorldAABB);
|
||||
|
||||
if (percentage < IntersectPercentage)
|
||||
return;
|
||||
|
||||
stun.Paralyze(5f);
|
||||
_slipped.Add(collidedWith.Uid);
|
||||
|
||||
if(!string.IsNullOrEmpty(SlipSound))
|
||||
EntitySystem.Get<AudioSystem>().PlayFromEntity(SlipSound, Owner, AudioHelpers.WithVariation(0.2f));
|
||||
}
|
||||
|
||||
public void Update(float frameTime)
|
||||
{
|
||||
foreach (var uid in _slipped.ToArray())
|
||||
{
|
||||
if(!uid.IsValid() || !_entityManager.EntityExists(uid)) continue;
|
||||
|
||||
var entity = _entityManager.GetEntity(uid);
|
||||
var collidable = Owner.GetComponent<ICollidableComponent>();
|
||||
var otherCollidable = entity.GetComponent<ICollidableComponent>();
|
||||
|
||||
if (!collidable.WorldAABB.Intersects(otherCollidable.WorldAABB))
|
||||
_slipped.Remove(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Content.Server/GameObjects/EntitySystems/SlipperySystem.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Content.Server.GameObjects.Components.Movement;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
public class SlipperySystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
EntityQuery = new TypeEntityQuery(typeof(SlipperyComponent));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var entity in RelevantEntities)
|
||||
{
|
||||
entity.GetComponent<SlipperyComponent>().Update(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Resources/Audio/Effects/slip.ogg
Normal file
@@ -3027,3 +3027,21 @@
|
||||
sprite: Objects/Consumable/Food/milkape.rsi
|
||||
- type: Icon
|
||||
sprite: Objects/Consumable/Food/milkape.rsi
|
||||
|
||||
- type: entity
|
||||
name: banana
|
||||
parent: FoodBase
|
||||
id: FoodBanana
|
||||
description: Rich in potassium.
|
||||
components:
|
||||
- type: Food
|
||||
trash: TrashBananaPeel
|
||||
- type: Solution
|
||||
contents:
|
||||
reagents:
|
||||
- ReagentId: chem.Nutriment
|
||||
Quantity: 6
|
||||
- type: Sprite
|
||||
sprite: Objects/Consumable/Food/banana.rsi
|
||||
- type: Icon
|
||||
sprite: Objects/Consumable/Food/banana.rsi
|
||||
|
||||
@@ -200,3 +200,16 @@
|
||||
sprite: Objects/Consumable/Trash/waffles.rsi
|
||||
- type: Icon
|
||||
sprite: Objects/Consumable/Trash/waffles.rsi
|
||||
|
||||
- type: entity
|
||||
name: banana peel
|
||||
parent: TrashBase
|
||||
id: TrashBananaPeel
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Consumable/Food/banana.rsi
|
||||
state: peel
|
||||
- type: Icon
|
||||
sprite: Objects/Consumable/Food/banana.rsi
|
||||
state: peel
|
||||
- type: Slippery
|
||||
|
||||
@@ -104,3 +104,92 @@
|
||||
- type: Item
|
||||
sprite: Objects/Specific/Janitorial/wet_floor_sign.rsi
|
||||
|
||||
- type: entity
|
||||
name: soap
|
||||
id: Soap
|
||||
parent: BaseItem
|
||||
description: A cheap bar of soap. Doesn't smell.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Janitorial/soap.rsi
|
||||
state: soap
|
||||
|
||||
- type: Icon
|
||||
sprite: Objects/Specific/Janitorial/soap.rsi
|
||||
state: soap
|
||||
|
||||
- type: Item
|
||||
sprite: Objects/Specific/Janitorial/soap.rsi
|
||||
|
||||
- type: Slippery
|
||||
paralyzeTime: 2.5
|
||||
|
||||
|
||||
- type: entity
|
||||
name: soap
|
||||
id: SoapNT
|
||||
parent: Soap
|
||||
description: A Nanotrasen brand bar of soap. Smells of phoron.
|
||||
components:
|
||||
- type: Sprite
|
||||
state: soapnt
|
||||
|
||||
- type: Icon
|
||||
state: soapnt
|
||||
|
||||
- type: entity
|
||||
name: soap
|
||||
id: SoapDeluxe
|
||||
parent: Soap
|
||||
description: A deluxe Waffle Co. brand bar of soap. Smells of condoms.
|
||||
components:
|
||||
- type: Sprite
|
||||
state: soapdeluxe
|
||||
|
||||
- type: Icon
|
||||
state: soapdeluxe
|
||||
|
||||
- type: entity
|
||||
name: soap
|
||||
id: SoapSyndie
|
||||
parent: Soap
|
||||
description: An untrustworthy bar of soap. Smells of fear.
|
||||
components:
|
||||
- type: Sprite
|
||||
state: soapsyndie
|
||||
|
||||
- type: Icon
|
||||
state: soapsyndie
|
||||
|
||||
- type: Slippery
|
||||
paralyzeTime: 5
|
||||
|
||||
- type: entity
|
||||
name: soap
|
||||
id: SoapHomemade
|
||||
parent: Soap
|
||||
description: A homemade bar of soap. Smells of... well....
|
||||
components:
|
||||
- type: Sprite
|
||||
state: soapgibs
|
||||
|
||||
- type: Icon
|
||||
state: soapgibs
|
||||
|
||||
- type: Slippery
|
||||
paralyzeTime: 2
|
||||
|
||||
- type: entity
|
||||
name: omega soap
|
||||
id: SoapOmega
|
||||
parent: Soap
|
||||
description: The most advanced soap known to mankind. Smells of bluespace.
|
||||
components:
|
||||
- type: Sprite
|
||||
state: soapomega
|
||||
|
||||
- type: Icon
|
||||
state: soapomega
|
||||
|
||||
- type: Slippery
|
||||
paralyzeTime: 7
|
||||
|
||||
BIN
Resources/Textures/Objects/Consumable/Food/banana.rsi/icon.png
Normal file
|
After Width: | Height: | Size: 488 B |
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA 3.0",
|
||||
"states": [
|
||||
{
|
||||
"name": "icon",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "peel",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/Objects/Consumable/Food/banana.rsi/peel.png
Normal file
|
After Width: | Height: | Size: 445 B |
|
Before Width: | Height: | Size: 575 B |
|
Before Width: | Height: | Size: 527 B |
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA 3.0",
|
||||
"copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at a407fc1f5c25cbce8b653c553f53be294d15b071 and https://github.com/tgstation/tgstation at 259acc8c81054d89f7b6bcd9ff702fdf587a19ed. soapomega.png modified by Zumorica",
|
||||
"states": [
|
||||
{
|
||||
"name": "soap",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "soapdeluxe",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "soapgibs",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "soapnt",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "soapomega",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "soapsyndie",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
1.0
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/Objects/Specific/Janitorial/soap.rsi/soap.png
Normal file
|
After Width: | Height: | Size: 688 B |
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 773 B |
|
After Width: | Height: | Size: 630 B |
|
After Width: | Height: | Size: 598 B |
|
After Width: | Height: | Size: 470 B |