New Traits (#13763)
This commit is contained in:
74
Content.Client/Traits/ParacusiaSystem.cs
Normal file
74
Content.Client/Traits/ParacusiaSystem.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using Content.Shared.Traits.Assorted;
|
||||||
|
using Content.Client.Camera;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Player;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Client.Traits;
|
||||||
|
|
||||||
|
public sealed class ParacusiaSystem : SharedParacusiaSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly IPlayerManager _player = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
[Dependency] private readonly CameraRecoilSystem _camera = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<ParacusiaComponent, ComponentStartup>(OnComponentStartup);
|
||||||
|
SubscribeLocalEvent<ParacusiaComponent, PlayerDetachedEvent>(OnPlayerDetach);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
if (!_timing.IsFirstTimePredicted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_player.LocalPlayer?.ControlledEntity is not EntityUid localPlayer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PlayParacusiaSounds(localPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnComponentStartup(EntityUid uid, ParacusiaComponent component, ComponentStartup args)
|
||||||
|
{
|
||||||
|
component.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(component.MinTimeBetweenIncidents, component.MaxTimeBetweenIncidents));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayerDetach(EntityUid uid, ParacusiaComponent component, PlayerDetachedEvent args)
|
||||||
|
{
|
||||||
|
component.Stream?.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayParacusiaSounds(EntityUid uid)
|
||||||
|
{
|
||||||
|
if (!TryComp<ParacusiaComponent>(uid, out var paracusia))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_timing.CurTime <= paracusia.NextIncidentTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Set the new time.
|
||||||
|
var timeInterval = _random.NextFloat(paracusia.MinTimeBetweenIncidents, paracusia.MaxTimeBetweenIncidents);
|
||||||
|
paracusia.NextIncidentTime += TimeSpan.FromSeconds(timeInterval);
|
||||||
|
|
||||||
|
// Offset position where the sound is played
|
||||||
|
var randomOffset =
|
||||||
|
new Vector2
|
||||||
|
(
|
||||||
|
_random.NextFloat(-paracusia.MaxSoundDistance, paracusia.MaxSoundDistance),
|
||||||
|
_random.NextFloat(-paracusia.MaxSoundDistance, paracusia.MaxSoundDistance)
|
||||||
|
);
|
||||||
|
|
||||||
|
var newCoords = Transform(uid).Coordinates.Offset(randomOffset);
|
||||||
|
|
||||||
|
// Play the sound
|
||||||
|
paracusia.Stream = _audio.PlayStatic(paracusia.Sounds, uid, newCoords);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ public sealed class Drunk : ReagentEffect
|
|||||||
/// BoozePower is how long each metabolism cycle will make the drunk effect last for.
|
/// BoozePower is how long each metabolism cycle will make the drunk effect last for.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("boozePower")]
|
[DataField("boozePower")]
|
||||||
public float BoozePower = 2f;
|
public float BoozePower = 3f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether speech should be slurred.
|
/// Whether speech should be slurred.
|
||||||
|
|||||||
8
Content.Server/Traits/Assorted/ParacusiaSystem.cs
Normal file
8
Content.Server/Traits/Assorted/ParacusiaSystem.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using Content.Shared.Traits.Assorted;
|
||||||
|
|
||||||
|
namespace Content.Server.Traits.Assorted;
|
||||||
|
|
||||||
|
public sealed class ParacusiaSystem : SharedParacusiaSystem
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Shared.Speech.EntitySystems;
|
using Content.Shared.Speech.EntitySystems;
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffect;
|
||||||
|
using Content.Shared.Traits.Assorted;
|
||||||
|
|
||||||
namespace Content.Shared.Drunk;
|
namespace Content.Shared.Drunk;
|
||||||
|
|
||||||
@@ -19,6 +20,9 @@ public abstract class SharedDrunkSystem : EntitySystem
|
|||||||
if (applySlur)
|
if (applySlur)
|
||||||
_slurredSystem.DoSlur(uid, TimeSpan.FromSeconds(boozePower), status);
|
_slurredSystem.DoSlur(uid, TimeSpan.FromSeconds(boozePower), status);
|
||||||
|
|
||||||
|
if (TryComp<LightweightDrunkComponent>(uid, out var trait))
|
||||||
|
boozePower *= trait.BoozeStrengthMultiplier;
|
||||||
|
|
||||||
if (!_statusEffectsSystem.HasStatusEffect(uid, DrunkKey, status))
|
if (!_statusEffectsSystem.HasStatusEffect(uid, DrunkKey, status))
|
||||||
{
|
{
|
||||||
_statusEffectsSystem.TryAddStatusEffect<DrunkComponent>(uid, DrunkKey, TimeSpan.FromSeconds(boozePower), true, status);
|
_statusEffectsSystem.TryAddStatusEffect<DrunkComponent>(uid, DrunkKey, TimeSpan.FromSeconds(boozePower), true, status);
|
||||||
|
|||||||
15
Content.Shared/Traits/Assorted/LightweightDrunkComponent.cs
Normal file
15
Content.Shared/Traits/Assorted/LightweightDrunkComponent.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Content.Shared.Drunk;
|
||||||
|
|
||||||
|
namespace Content.Shared.Traits.Assorted;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used for the lightweight trait. DrunkSystem will check for this component and modify the boozePower accordingly if it finds it.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
[Access(typeof(SharedDrunkSystem))]
|
||||||
|
public sealed class LightweightDrunkComponent : Component
|
||||||
|
{
|
||||||
|
[DataField("boozeStrengthMultiplier"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float BoozeStrengthMultiplier = 4f;
|
||||||
|
}
|
||||||
61
Content.Shared/Traits/Assorted/ParacusiaComponent.cs
Normal file
61
Content.Shared/Traits/Assorted/ParacusiaComponent.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using System;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
|
namespace Content.Shared.Traits.Assorted;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component is used for paracusia, which causes auditory hallucinations.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
[Access(typeof(SharedParacusiaSystem))]
|
||||||
|
public sealed class ParacusiaComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum time between incidents in seconds
|
||||||
|
/// </summary>
|
||||||
|
[DataField("maxTimeBetweenIncidents", required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float MaxTimeBetweenIncidents = 30f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum time between incidents in seconds
|
||||||
|
/// </summary>
|
||||||
|
[DataField("minTimeBetweenIncidents", required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float MinTimeBetweenIncidents = 60f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How far away at most can the sound be?
|
||||||
|
/// </summary>
|
||||||
|
[DataField("maxSoundDistance", required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float MaxSoundDistance;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The sounds to choose from
|
||||||
|
/// </summary>
|
||||||
|
[DataField("sounds", required: true)]
|
||||||
|
public SoundSpecifier Sounds = default!;
|
||||||
|
|
||||||
|
[DataField("timeBetweenIncidents", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public TimeSpan NextIncidentTime;
|
||||||
|
|
||||||
|
public IPlayingAudioStream? Stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class ParacusiaComponentState : ComponentState
|
||||||
|
{
|
||||||
|
public readonly float MaxTimeBetweenIncidents;
|
||||||
|
public readonly float MinTimeBetweenIncidents;
|
||||||
|
public readonly float MaxSoundDistance;
|
||||||
|
public readonly SoundSpecifier Sounds = default!;
|
||||||
|
|
||||||
|
public ParacusiaComponentState(float maxTimeBetweenIncidents, float minTimeBetweenIncidents, float maxSoundDistance, SoundSpecifier sounds)
|
||||||
|
{
|
||||||
|
MaxTimeBetweenIncidents = maxTimeBetweenIncidents;
|
||||||
|
MinTimeBetweenIncidents = minTimeBetweenIncidents;
|
||||||
|
MaxSoundDistance = maxSoundDistance;
|
||||||
|
Sounds = sounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
30
Content.Shared/Traits/Assorted/SharedParacusiaSystem.cs
Normal file
30
Content.Shared/Traits/Assorted/SharedParacusiaSystem.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.Traits.Assorted;
|
||||||
|
|
||||||
|
public abstract class SharedParacusiaSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<ParacusiaComponent, ComponentGetState>(GetCompState);
|
||||||
|
SubscribeLocalEvent<ParacusiaComponent, ComponentHandleState>(HandleCompState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetCompState(EntityUid uid, ParacusiaComponent component, ref ComponentGetState args)
|
||||||
|
{
|
||||||
|
args.State = new ParacusiaComponentState(component.MaxTimeBetweenIncidents, component.MinTimeBetweenIncidents, component.MaxSoundDistance, component.Sounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleCompState(EntityUid uid, ParacusiaComponent component, ref ComponentHandleState args)
|
||||||
|
{
|
||||||
|
if (args.Current is not ParacusiaComponentState state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
component.MaxTimeBetweenIncidents = state.MaxTimeBetweenIncidents;
|
||||||
|
component.MinTimeBetweenIncidents = state.MinTimeBetweenIncidents;
|
||||||
|
component.MaxSoundDistance = state.MaxSoundDistance;
|
||||||
|
component.Sounds = state.Sounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,3 +10,12 @@ trait-sneezing-name = Runny nose
|
|||||||
trait-sneezing-desc = You sneeze and cough uncontrollably
|
trait-sneezing-desc = You sneeze and cough uncontrollably
|
||||||
|
|
||||||
permanent-blindness-trait-examined = [color=lightblue]{CAPITALIZE(POSS-ADJ($target))} eyes are glassy and unfocused. It doesn't seem like {SUBJECT($target)} can see you.[/color]
|
permanent-blindness-trait-examined = [color=lightblue]{CAPITALIZE(POSS-ADJ($target))} eyes are glassy and unfocused. It doesn't seem like {SUBJECT($target)} can see you.[/color]
|
||||||
|
|
||||||
|
trait-lightweight-name = Lightweight Drunk
|
||||||
|
trait-lightweight-desc = Alcohol has a stronger effect on you
|
||||||
|
|
||||||
|
trait-muted-name = Muted
|
||||||
|
trait-muted-desc = You can't speak
|
||||||
|
|
||||||
|
trait-paracusia-name = Paracusia
|
||||||
|
trait-paracusia-desc = You hear sounds that aren't really there
|
||||||
|
|||||||
76
Resources/Prototypes/SoundCollections/traits.yml
Normal file
76
Resources/Prototypes/SoundCollections/traits.yml
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
- type: soundCollection
|
||||||
|
id: Paracusia
|
||||||
|
files:
|
||||||
|
#- /Audio/Effects/adminhelp.ogg
|
||||||
|
#- /Audio/Machines/Nuke/nuke_alarm.ogg
|
||||||
|
#- /Audio/Misc/emergency_meeting.ogg
|
||||||
|
- /Audio/Effects/countdown.ogg
|
||||||
|
- /Audio/Effects/explosion1.ogg
|
||||||
|
- /Audio/Effects/explosion2.ogg
|
||||||
|
- /Audio/Effects/explosion3.ogg
|
||||||
|
- /Audio/Effects/explosion4.ogg
|
||||||
|
- /Audio/Effects/explosion5.ogg
|
||||||
|
- /Audio/Effects/explosion6.ogg
|
||||||
|
- /Audio/Effects/glass_break1.ogg
|
||||||
|
- /Audio/Effects/glass_break2.ogg
|
||||||
|
- /Audio/Effects/glass_break3.ogg
|
||||||
|
- /Audio/Effects/bodyfall1.ogg
|
||||||
|
- /Audio/Effects/bodyfall2.ogg
|
||||||
|
- /Audio/Effects/bodyfall3.ogg
|
||||||
|
- /Audio/Effects/bodyfall4.ogg
|
||||||
|
- /Audio/Effects/demon_dies.ogg
|
||||||
|
- /Audio/Effects/demon_attack1.ogg
|
||||||
|
- /Audio/Effects/bang.ogg
|
||||||
|
- /Audio/Effects/clang.ogg
|
||||||
|
- /Audio/Effects/metalbreak.ogg
|
||||||
|
- /Audio/Effects/minibombcountdown.ogg
|
||||||
|
- /Audio/Effects/sadtrombone.ogg
|
||||||
|
- /Audio/Effects/sparks1.ogg
|
||||||
|
- /Audio/Effects/sparks2.ogg
|
||||||
|
- /Audio/Effects/sparks3.ogg
|
||||||
|
- /Audio/Effects/sparks4.ogg
|
||||||
|
- /Audio/Effects/radpulse1.ogg
|
||||||
|
- /Audio/Effects/radpulse5.ogg
|
||||||
|
- /Audio/Effects/radpulse9.ogg
|
||||||
|
- /Audio/Effects/Chemistry/bubbles.ogg
|
||||||
|
- /Audio/Machines/airlock_close.ogg
|
||||||
|
- /Audio/Machines/airlock_deny.ogg
|
||||||
|
- /Audio/Machines/airlock_open.ogg
|
||||||
|
- /Audio/Machines/airlock_ext_open.ogg
|
||||||
|
- /Audio/Machines/anomaly_generate.ogg
|
||||||
|
- /Audio/Machines/phasein.ogg
|
||||||
|
- /Audio/Machines/vending_restock_start.ogg
|
||||||
|
- /Audio/Machines/vending_restock_done.ogg
|
||||||
|
- /Audio/Magic/disintegrate.ogg
|
||||||
|
- /Audio/Magic/staff_animation.ogg
|
||||||
|
- /Audio/Weapons/ebladeon.ogg
|
||||||
|
- /Audio/Weapons/smash.ogg
|
||||||
|
- /Audio/Weapons/bladeslice.ogg
|
||||||
|
- /Audio/Weapons/punch1.ogg
|
||||||
|
- /Audio/Weapons/punch2.ogg
|
||||||
|
- /Audio/Weapons/punch3.ogg
|
||||||
|
- /Audio/Weapons/punch4.ogg
|
||||||
|
- /Audio/Weapons/genhit1.ogg
|
||||||
|
- /Audio/Weapons/Guns/Hits/bullet_hit.ogg
|
||||||
|
- /Audio/Weapons/Guns/Hits/snap.ogg
|
||||||
|
- /Audio/Weapons/Guns/Gunshots/atreides.ogg
|
||||||
|
- /Audio/Weapons/Guns/Gunshots/c-20r.ogg
|
||||||
|
- /Audio/Weapons/Guns/Gunshots/pistol.ogg
|
||||||
|
- /Audio/Items/bikehorn.ogg
|
||||||
|
- /Audio/Items/Toys/weh.ogg
|
||||||
|
- /Audio/Items/Toys/toysqueak1.ogg
|
||||||
|
- /Audio/Items/Toys/toysqueak2.ogg
|
||||||
|
- /Audio/Items/Toys/toysqueak3.ogg
|
||||||
|
- /Audio/Voice/Talk/lizard.ogg
|
||||||
|
- /Audio/Voice/Talk/pai.ogg
|
||||||
|
- /Audio/Voice/Talk/speak_1.ogg
|
||||||
|
- /Audio/Voice/Talk/speak_2_ask.ogg
|
||||||
|
- /Audio/Voice/Talk/speak_3_exclaim.ogg
|
||||||
|
- /Audio/Voice/Human/malescream_1.ogg
|
||||||
|
- /Audio/Voice/Human/malescream_6.ogg
|
||||||
|
- /Audio/Voice/Human/femalescream_2.ogg
|
||||||
|
- /Audio/Voice/Human/femalescream_4.ogg
|
||||||
|
- /Audio/Voice/Zombie/zombie-1.ogg
|
||||||
|
- /Audio/Voice/Zombie/zombie-2.ogg
|
||||||
|
- /Audio/Voice/Zombie/zombie-3.ogg
|
||||||
|
- /Audio/Voice/Vox/shriek1.ogg
|
||||||
@@ -22,3 +22,22 @@
|
|||||||
name: trait-pacifist-name
|
name: trait-pacifist-name
|
||||||
components:
|
components:
|
||||||
- type: Pacifist
|
- type: Pacifist
|
||||||
|
|
||||||
|
- type: trait
|
||||||
|
id: Paracusia
|
||||||
|
name: trait-paracusia-name
|
||||||
|
description: trait-paracusia-desc
|
||||||
|
components:
|
||||||
|
- type: Paracusia
|
||||||
|
minTimeBetweenIncidents: 0.1
|
||||||
|
maxTimeBetweenIncidents: 300
|
||||||
|
maxSoundDistance: 7
|
||||||
|
sounds:
|
||||||
|
collection: Paracusia
|
||||||
|
|
||||||
|
- type: trait
|
||||||
|
id: Muted
|
||||||
|
name: trait-muted-name
|
||||||
|
description: trait-muted-desc
|
||||||
|
components:
|
||||||
|
- type: Muted
|
||||||
|
|||||||
@@ -12,3 +12,11 @@
|
|||||||
params:
|
params:
|
||||||
variation: 0.2
|
variation: 0.2
|
||||||
timeBetweenIncidents: 0.3, 300
|
timeBetweenIncidents: 0.3, 300
|
||||||
|
|
||||||
|
- type: trait
|
||||||
|
id: LightweightDrunk
|
||||||
|
name: trait-lightweight-name
|
||||||
|
description: trait-lightweight-desc
|
||||||
|
components:
|
||||||
|
- type: LightweightDrunk
|
||||||
|
boozeStrengthMultiplier: 2
|
||||||
|
|||||||
Reference in New Issue
Block a user