Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Trait] Sight Fear trait #85

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Robust.Shared.Audio;

namespace Content.Server.SimpleStation14.Traits.SightFear
{
[RegisterComponent]
public sealed class SightFearTraitComponent : Component
{
/// <summary>
/// The ID of the fear this entity has
/// Matches this to fearable entities with the same ID and adds to <see cref="Fear"/>
/// If empty, a random fear will be picked from the weighted random prototype "RandomFears"
/// </summary>
[DataField("afraidOf")]
[ViewVariables(VVAccess.ReadWrite)]
public string AfraidOf = string.Empty;

/// <summary>
/// How much fear this entity has.
/// Goes up to <see cref="MaxFear"/> before the effects of fear start to kick in
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public double Fear = 0;

/// <summary>
/// How much fear this entity can have before the effects of fear start to kick in
/// </summary>
[DataField("maxFear")]
[ViewVariables(VVAccess.ReadWrite)]
public double MaxFear = 20;

/// <summary>
/// If this entity is currently afraid
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public bool Afraid = false;

/// <summary>
/// How fast the entity's fear goes down
/// </summary>
[DataField("calmRate")]
[ViewVariables(VVAccess.ReadWrite)]
public float CalmRate = 2.25f;

public IPlayingAudioStream? Stream;

public float Accumulator = 0.084f;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using System.Linq;
using Content.Server.Power.EntitySystems;
using Content.Shared.Audio;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Examine;
using Content.Shared.Interaction.Helpers;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;

namespace Content.Server.SimpleStation14.Traits.SightFear;

public sealed class SightFearTraitSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly IEntityManager _entity = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly AudioSystem _audio = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<SightFearTraitComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<SightFearedComponent, ComponentInit>(CheckFeared);
}


private void OnComponentInit(EntityUid uid, SightFearTraitComponent component, ComponentInit args)
{
// If the entity already has a fear, don't overwrite it
// Check for RandomFears prototype
if (!string.IsNullOrEmpty(component.AfraidOf) ||
!_prototype.TryIndex<WeightedRandomPrototype>("RandomFears", out var randomFears))
return;

// Pick a random fear and use it
component.AfraidOf = randomFears.Pick(_random);

// Mark the component as dirty so it gets synced to the client
Dirty(component);
}

private void CheckFeared(EntityUid uid, SightFearedComponent component, ComponentInit args)
{
// Check if the entity has any fears defined
if (component.Fears.Count == 0)
{
Logger.WarningS("SightFearTraitSystem", $"Entity {uid} has SightFearedComponent without any defined fears.");
return;
}

// Check if the RandomFears prototype exists
if (!_prototype.TryIndex<WeightedRandomPrototype>("RandomFears", out var randomFears))
{
Logger.ErrorS("SightFearTraitSystem", $"Prototype RandomFears could not be found.");
return;
}

// Check if the fears defined on the entity are in the RandomFears prototype
foreach (var fear in component.Fears.Keys.Where(fear => !randomFears.Weights.ContainsKey(fear)))
{
Logger.ErrorS("SightFearTraitSystem", $"Prototype RandomFears does not contain fear {fear} from SightFearedComponent on entity {uid}.");
}
}

public override void Update(float frameTime)
{
base.Update(frameTime);

// Loop through all entities with SightFearTraitComponent
var query = EntityQueryEnumerator<SightFearTraitComponent>();
while(query.MoveNext(out var uid, out var component))
{
// Await the accumulator
if (component.Accumulator > 0f)
{
component.Accumulator -= frameTime;
continue;
}

// Reset the accumulator
component.Accumulator = 0.084f;

// Get the range the entity can see based on their eye component
var range = 10f;
if (_entity.TryGetComponent<SharedEyeComponent>(uid, out var eye))
range *= (eye.Zoom.X + eye.Zoom.Y) / 2;

// Get all entities in range that have a SightFearedComponent
var entities = _lookup.GetEntitiesInRange(Transform(uid).Coordinates, range)
.Where(e => _entity.HasComponent<SightFearedComponent>(e));

var afraid = false;

// Loop through all fear inflicters
foreach (var entity in entities)
{
// Check if the fear inflicter is in range and unoccluded (visible)
if (!_entity.TryGetComponent<ExaminerComponent>(uid, out var examiner) ||
!examiner.InRangeUnOccluded(Transform(entity).Coordinates, range))
continue;

// Check if the afraid should be afraid of the fear inflicter
var feared = _entity.GetComponent<SightFearedComponent>(entity);
if (!feared.Fears.TryGetValue(component.AfraidOf, out var value))
continue;

// Calculate the strength of the fear
var distance = (Transform(uid).Coordinates.Position - Transform(entity).Coordinates.Position).Length;
var strength = MathHelper.Lerp(0f, value, 1f - distance / range);

if (strength <= 0f)
continue;

// Increase the level of fear
afraid = true;
component.Fear += strength;

// TODO: Do something when afraid
Logger.ErrorS("SightFearTraitSystem", $"Entity {uid} is afraid of {entity} ({component.AfraidOf}) at strength {strength}, now at a fear level of {component.Fear}/{component.MaxFear}.");
}

// Set the afraid state for other systems to use
component.Afraid = afraid;

// Spook
if (component.Fear >= component.MaxFear * 2 && component.Stream == null)
{
component.Stream = _audio.PlayGlobal(new SoundPathSpecifier("/Audio/SimpleStation14/Effects/fastbeat.ogg"), uid, AudioParams.Default.WithLoop(true).WithVariation(0.125f));
}
else if (component.Fear >= component.MaxFear && component.Stream == null)
{
component.Stream = _audio.PlayGlobal(new SoundPathSpecifier("/Audio/SimpleStation14/Effects/slowbeat.ogg"), uid, AudioParams.Default.WithLoop(true).WithVariation(0.125f));
}
else if (component.Fear < component.MaxFear && component.Stream != null)
{
component.Stream?.Stop();
component.Stream = null;
}

// Decrease the fear level if not afraid this frame
if (!afraid && component.Fear > 0f)
{
component.Fear -= frameTime * 1.19047619 * component.CalmRate; // Don't ask about the number.
Logger.ErrorS("SightFearTraitSystem", $"Entity {uid} is not afraid, decreasing fear level to {component.Fear}/{component.MaxFear}.");
}

// Clamp the fear level
component.Fear = Math.Clamp(component.Fear, 0, component.MaxFear * 2);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Content.Server.SimpleStation14.Traits.SightFear
{
[RegisterComponent]
public sealed class SightFearedComponent : Component
{
/// <summary>
/// The fears this entity inflicts, and their power
/// </summary>
[DataField("fears")]
[ViewVariables(VVAccess.ReadWrite)]
public Dictionary<string, float> Fears = new();
}
}
Binary file not shown.
Binary file not shown.
5 changes: 4 additions & 1 deletion Resources/Prototypes/Catalog/Fills/Boxes/medical.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
layers:
- state: box
- state: syringe
- type: SightFeared
fears:
Trypanophobia: 2

- type: entity
name: pill canister box
Expand Down Expand Up @@ -72,7 +75,7 @@
layers:
- state: box
- state: latex

- type: entity
name: nitrile gloves box
parent: BoxCardboard
Expand Down
15 changes: 15 additions & 0 deletions Resources/Prototypes/Entities/Effects/lightning.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
- type: Tag
tags:
- HideContextMenu
- type: SightFeared
fears:
Astraphobia: 2.5 # Doesn't show very long, make it spooky

- type: entity
name: lightning
Expand Down Expand Up @@ -60,6 +63,9 @@
- type: Lightning
canArc: false
shockDamage: 30
- type: SightFeared
fears:
Astraphobia: 3.25 # Spookier

- type: entity
name: charged lightning
Expand All @@ -78,6 +84,9 @@
- type: Lightning
canArc: true
lightningPrototype: ChargedLightning
- type: SightFeared
fears:
Astraphobia: 2.75

- type: entity
name: supercharged lightning
Expand All @@ -103,6 +112,9 @@
softness: 1
autoRot: true
castShadows: false
- type: SightFeared
fears:
Astraphobia: 3

- type: entity
name: hypercharged lightning
Expand All @@ -128,3 +140,6 @@
softness: 1
autoRot: true
castShadows: false
- type: SightFeared
fears:
Astraphobia: 3.25
3 changes: 3 additions & 0 deletions Resources/Prototypes/Entities/Effects/puddle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@
- type: Puddle
overflowVolume: 50
opacityModifier: 8
- type: SightFeared
fears:
Hemophobia: 0.5

- type: entity
name: vomit
Expand Down
15 changes: 15 additions & 0 deletions Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@
- type: SentienceTarget
flavorKind: station-event-random-sentience-flavor-organic
- type: RandomBark
- type: SightFeared
fears:
Ornithophobia: 0.5

- type: entity
name: mallard duck #Quack
Expand Down Expand Up @@ -1111,6 +1114,9 @@
- type: NoSlip
- type: HTN
rootTask: IdleEvadeCompound
- type: SightFeared
fears:
Ornithophobia: 0.75 # A bit spookier than the other birds

- type: entity
name: penguin
Expand Down Expand Up @@ -1174,6 +1180,9 @@
barks:
- Wank
barkMultiplier: 0.6
- type: SightFeared
fears:
Ornithophobia: 0.5

- type: entity
name: grenade penguin
Expand Down Expand Up @@ -1298,6 +1307,9 @@
- Hsssssss
- Hss
- Hsssss
- type: SightFeared
fears:
Ophidiophobia: 1.5

# Code unique spider prototypes or combine them all into one spider and get a
# random sprite state when you spawn it.
Expand Down Expand Up @@ -1362,6 +1374,9 @@
types:
Piercing: 10
- type: RandomBark
- type: SightFeared
fears:
Arachnophobia: 1

- type: entity
name: tarantula
Expand Down
3 changes: 3 additions & 0 deletions Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@
- type: ActiveRadio
channels:
- XenoHive
- type: SightFeared
fears:
Xenophobia: 5 # Fucking SPOOKY

# NPC versions

Expand Down
3 changes: 3 additions & 0 deletions Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,6 @@
- type: SpellbookUser2
- type: Inventory
templateId: aghost
- type: SightFeared
fears:
Phasmophobia: 2 # Spooky ghosts are spooky
4 changes: 4 additions & 0 deletions Resources/Prototypes/Entities/Mobs/Player/diona.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@
- type: Faction
factions:
- NanoTrasen
- type: SightFeared
fears:
Anthropophobia: 0.75
Xenophobia: 0.75
3 changes: 3 additions & 0 deletions Resources/Prototypes/Entities/Mobs/Player/dwarf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@
- NanoTrasen
- type: MailReceiver
- type: PotentialPsionic
- type: SightFeared
fears:
Anthropophobia: 0.8 # A bit shorter, so less scary
3 changes: 3 additions & 0 deletions Resources/Prototypes/Entities/Mobs/Player/human.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
- NanoTrasen
- type: MailReceiver
- type: PotentialPsionic
- type: SightFeared
fears:
Anthropophobia: 1

#Syndie
- type: entity
Expand Down
3 changes: 3 additions & 0 deletions Resources/Prototypes/Entities/Mobs/Player/observer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,6 @@
- type: MovementIgnoreGravity
- type: Pullable
- type: Speech
- type: SightFeared
fears:
Phasmophobia: 1
Loading