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.
|
||||
/// </summary>
|
||||
[DataField("boozePower")]
|
||||
public float BoozePower = 2f;
|
||||
public float BoozePower = 3f;
|
||||
|
||||
/// <summary>
|
||||
/// 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.StatusEffect;
|
||||
using Content.Shared.Traits.Assorted;
|
||||
|
||||
namespace Content.Shared.Drunk;
|
||||
|
||||
@@ -19,6 +20,9 @@ public abstract class SharedDrunkSystem : EntitySystem
|
||||
if (applySlur)
|
||||
_slurredSystem.DoSlur(uid, TimeSpan.FromSeconds(boozePower), status);
|
||||
|
||||
if (TryComp<LightweightDrunkComponent>(uid, out var trait))
|
||||
boozePower *= trait.BoozeStrengthMultiplier;
|
||||
|
||||
if (!_statusEffectsSystem.HasStatusEffect(uid, DrunkKey, 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
|
||||
|
||||
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
|
||||
components:
|
||||
- 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:
|
||||
variation: 0.2
|
||||
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