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

Added the revenant Haunt action #293

Merged
merged 6 commits into from
Sep 20, 2024
Merged
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
56 changes: 56 additions & 0 deletions Content.Client/Revenant/RevenantRegenModifierSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Numerics;
using Content.Client.Alerts;
using Content.Shared.Revenant;
using Content.Shared.Revenant.Components;
using Robust.Client.GameObjects;
using Robust.Client.Player;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using Timer = Robust.Shared.Timing.Timer;

namespace Content.Client.Revenant;

public sealed class RevenantRegenModifierSystem : EntitySystem
{
[Dependency] private readonly SpriteSystem _sprite = default!;

private readonly SpriteSpecifier _witnessIndicator = new SpriteSpecifier.Texture(new ResPath("Interface/Actions/scream.png"));

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

SubscribeLocalEvent<RevenantRegenModifierComponent, UpdateAlertSpriteEvent>(OnUpdateAlert);
SubscribeNetworkEvent<RevenantHauntWitnessEvent>(OnWitnesses);
}

private void OnWitnesses(RevenantHauntWitnessEvent args)
{
foreach (var witness in args.Witnesses)
{
var ent = GetEntity(witness);
if (TryComp<SpriteComponent>(ent, out var sprite))
{
var layerID = sprite.AddLayer(_witnessIndicator);
if (sprite.TryGetLayer(layerID, out var layer))
{
layer.Offset = new Vector2(0, 0.8f);
layer.Scale = new Vector2(0.65f, 0.65f);
}
Timer.Spawn(TimeSpan.FromSeconds(5), () => sprite.RemoveLayer(layerID));
}
}
}

private void OnUpdateAlert(Entity<RevenantRegenModifierComponent> ent, ref UpdateAlertSpriteEvent args)
{
if (args.Alert.ID != ent.Comp.Alert)
return;

var sprite = args.SpriteViewEnt.Comp;
var witnesses = Math.Clamp(ent.Comp.Witnesses.Count, 0, 99);
sprite.LayerSetState(RevenantVisualLayers.Digit1, $"{witnesses / 10}");
sprite.LayerSetState(RevenantVisualLayers.Digit2, $"{witnesses % 10}");
}
}
65 changes: 65 additions & 0 deletions Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction.Components;
using Robust.Shared.Player;
using Content.Shared.StatusEffect;
using Content.Shared.Flash.Components;
using Robust.Shared.Audio.Systems;

namespace Content.Server.Revenant.EntitySystems;

Expand All @@ -48,6 +52,13 @@ public sealed partial class RevenantSystem
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly RevenantAnimatedSystem _revenantAnimated = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;

[ValidatePrototypeId<StatusEffectPrototype>]
private const string RevenantEssenceRegen = "EssenceRegen";

[ValidatePrototypeId<StatusEffectPrototype>]
private const string FlashedId = "Flashed";

private void InitializeAbilities()
{
Expand All @@ -61,6 +72,7 @@ private void InitializeAbilities()
SubscribeLocalEvent<RevenantComponent, RevenantMalfunctionActionEvent>(OnMalfunctionAction);
SubscribeLocalEvent<RevenantComponent, RevenantBloodWritingEvent>(OnBloodWritingAction);
SubscribeLocalEvent<RevenantComponent, RevenantAnimateEvent>(OnAnimateAction);
SubscribeLocalEvent<RevenantComponent, RevenantHauntActionEvent>(OnHauntAction);
}

private void OnInteract(EntityUid uid, RevenantComponent component, UserActivateInWorldEvent args)
Expand Down Expand Up @@ -220,6 +232,59 @@ private void OnHarvest(EntityUid uid, RevenantComponent component, HarvestEvent
args.Handled = true;
}

private void OnHauntAction(EntityUid uid, RevenantComponent comp, RevenantHauntActionEvent args)
{
if (args.Handled)
return;

if (!TryUseAbility(uid, comp, 0, comp.HauntDebuffs))
return;

args.Handled = true;

// This is probably not the right way to do this...
var witnessAndRevenantFilter = Filter.Pvs(uid).RemoveWhere(player =>
{
if (player.AttachedEntity == null)
return true;

var ent = player.AttachedEntity.Value;

if (!HasComp<MobStateComponent>(ent) || !HasComp<HumanoidAppearanceComponent>(ent) || HasComp<RevenantComponent>(ent))
return true;

return !_interact.InRangeUnobstructed((uid, Transform(uid)), (ent, Transform(ent)), range: 0, collisionMask: CollisionGroup.Impassable);
});

var witnesses = new HashSet<NetEntity>(witnessAndRevenantFilter.RemovePlayerByAttachedEntity(uid).Recipients.Select(ply => GetNetEntity(ply.AttachedEntity!.Value)));

// Give the witnesses a spook!
_audioSystem.PlayGlobal(comp.HauntSound, witnessAndRevenantFilter, true);

foreach (var witness in witnesses)
{
_statusEffects.TryAddStatusEffect<FlashedComponent>(GetEntity(witness),
FlashedId,
comp.HauntFlashDuration,
false
);
}

if (witnesses.Count > 0 && _statusEffects.TryAddStatusEffect(uid,
RevenantEssenceRegen,
comp.HauntEssenceRegenDuration,
true,
component: new RevenantRegenModifierComponent(witnesses)
))
{
if (_mind.TryGetMind(uid, out var _, out var mind) && mind.Session != null)
RaiseNetworkEvent(new RevenantHauntWitnessEvent(witnesses), mind.Session);

_store.TryAddCurrency(new Dictionary<string, FixedPoint2>
{ {comp.StolenEssenceCurrencyPrototype, comp.HauntStolenEssencePerWitness * witnesses.Count} }, uid);
}
}

private void OnDefileAction(EntityUid uid, RevenantComponent component, RevenantDefileActionEvent args)
{
if (args.Handled)
Expand Down
13 changes: 11 additions & 2 deletions Content.Server/Revenant/EntitySystems/RevenantSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public sealed partial class RevenantSystem : EntitySystem
[ValidatePrototypeId<EntityPrototype>]
private const string RevenantShopId = "ActionRevenantShop";

[ValidatePrototypeId<EntityPrototype>]
private const string RevenantHauntId = "ActionRevenantHaunt";

public override void Initialize()
{
base.Initialize();
Expand Down Expand Up @@ -98,7 +101,8 @@ private void OnStartup(EntityUid uid, RevenantComponent component, ComponentStar

private void OnMapInit(EntityUid uid, RevenantComponent component, MapInitEvent args)
{
_action.AddAction(uid, ref component.Action, RevenantShopId);
_action.AddAction(uid, ref component.ShopAction, RevenantShopId);
_action.AddAction(uid, ref component.HauntAction, RevenantHauntId);
}

private void OnStatusAdded(EntityUid uid, RevenantComponent component, StatusEffectAddedEvent args)
Expand Down Expand Up @@ -232,7 +236,12 @@ public override void Update(float frameTime)

if (rev.Essence < rev.EssenceRegenCap)
{
ChangeEssenceAmount(uid, rev.EssencePerSecond, rev, regenCap: true);
var essence = rev.EssencePerSecond;

if (TryComp<RevenantRegenModifierComponent>(uid, out var regen))
essence += rev.HauntEssenceRegenPerWitness * regen.Witnesses.Count;

ChangeEssenceAmount(uid, essence, rev, regenCap: true);
}
}
}
Expand Down
28 changes: 27 additions & 1 deletion Content.Shared/Revenant/Components/RevenantComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Content.Shared.FixedPoint;
using Content.Shared.Store;
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
Expand Down Expand Up @@ -92,6 +93,30 @@ public sealed partial class RevenantComponent : Component
public float MaxEssenceUpgradeAmount = 10;
#endregion

// When used, the revenant reveals itself temporarily and gains stolen essence and a boost in
// essence regeneration for each crewmate that witnesses it
#region Haunt Ability

[DataField("hauntDebuffs"), ViewVariables(VVAccess.ReadWrite)]
public Vector2 HauntDebuffs = new(2, 6);

[DataField("hauntStolenEssencePerWitness"), ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 HauntStolenEssencePerWitness = 2.5;

[DataField("hauntEssenceRegenPerWitness"), ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 HauntEssenceRegenPerWitness = 0.5;

[DataField("hauntEssenceRegenDuration"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan HauntEssenceRegenDuration = TimeSpan.FromSeconds(10);

[DataField("hauntSound"), ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier? HauntSound = new SoundCollectionSpecifier("RevenantHaunt");

[DataField("hauntFlashDuration"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan HauntFlashDuration = TimeSpan.FromSeconds(2);

#endregion

//In the nearby radius, causes various objects to be thrown, messed with, and containers opened
//Generally just causes a mess
#region Defile Ability
Expand Down Expand Up @@ -260,5 +285,6 @@ public sealed partial class RevenantComponent : Component
public string HarvestingState = "harvesting";
#endregion

[DataField] public EntityUid? Action;
[DataField] public EntityUid? ShopAction;
[DataField] public EntityUid? HauntAction;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Content.Shared.Alert;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;

namespace Content.Shared.Revenant.Components;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class RevenantRegenModifierComponent : Component
{
[ViewVariables, AutoNetworkedField]
public HashSet<NetEntity> Witnesses;

[DataField]
public ProtoId<AlertPrototype> Alert = "EssenceRegen";

public RevenantRegenModifierComponent(HashSet<NetEntity> witnesses)
{
Witnesses = witnesses;
}

public RevenantRegenModifierComponent() : this(new())
{
}
}
19 changes: 19 additions & 0 deletions Content.Shared/Revenant/SharedRevenant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public sealed partial class RevenantShopActionEvent : InstantActionEvent
{
}

public sealed partial class RevenantHauntActionEvent : InstantActionEvent
{
}

public sealed partial class RevenantDefileActionEvent : InstantActionEvent
{
}
Expand All @@ -70,6 +74,21 @@ public sealed partial class RevenantAnimateEvent : EntityTargetActionEvent
{
}

[Serializable, NetSerializable]
public sealed partial class RevenantHauntWitnessEvent : EntityEventArgs
{
public HashSet<NetEntity> Witnesses = new();

public RevenantHauntWitnessEvent(HashSet<NetEntity> witnesses)
{
Witnesses = witnesses;
}

public RevenantHauntWitnessEvent() : this(new())
{
}
}

[Serializable, NetSerializable]
public sealed partial class ExorciseRevenantDoAfterEvent : SimpleDoAfterEvent
{
Expand Down
16 changes: 16 additions & 0 deletions Content.Shared/StatusEffect/StatusEffectsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,22 @@ public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool re
return false;
}

public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, Component component,
StatusEffectsComponent? status = null)
{
if (!Resolve(uid, ref status, false))
return false;

if (TryAddStatusEffect(uid, key, time, refresh, status))
{
EntityManager.AddComponent(uid, component, true);
status.ActiveEffects[key].RelevantComponent = _componentFactory.GetComponentName(component.GetType());
return true;
}

return false;
}

/// <summary>
/// Tries to add a status effect to an entity with a certain timer.
/// </summary>
Expand Down
24 changes: 24 additions & 0 deletions Resources/Audio/Effects/Revenant/attributions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
- files: ["haunt0.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Sound originally derived from SCP: Containment breach."
source: "https://github.com/Regalis11/scpcb/blob/edb8fe0840b78f14d1aef3a0bf6174630e7be296/SFX/Horror/Horror0.ogg"

- files: ["haunt1.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Sound originally derived from SCP: Containment breach."
source: "https://github.com/Regalis11/scpcb/blob/edb8fe0840b78f14d1aef3a0bf6174630e7be296/SFX/Horror/Horror4.ogg"

- files: ["haunt2.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Sound originally derived from SCP: Containment breach."
source: "https://github.com/Regalis11/scpcb/blob/edb8fe0840b78f14d1aef3a0bf6174630e7be296/SFX/Horror/Horror6.ogg"

- files: ["haunt3.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Sound originally derived from SCP: Containment breach."
source: "https://github.com/Regalis11/scpcb/blob/edb8fe0840b78f14d1aef3a0bf6174630e7be296/SFX/Horror/Horror11.ogg"

- files: ["haunt4.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Sound originally derived from SCP: Containment breach. Edited down to a shorter length by TGRCDev."
source: "https://github.com/Regalis11/scpcb/blob/edb8fe0840b78f14d1aef3a0bf6174630e7be296/SFX/Horror/Horror12.ogg"
Binary file added Resources/Audio/Effects/Revenant/haunt0.ogg
Binary file not shown.
Binary file added Resources/Audio/Effects/Revenant/haunt1.ogg
Binary file not shown.
Binary file added Resources/Audio/Effects/Revenant/haunt2.ogg
Binary file not shown.
Binary file added Resources/Audio/Effects/Revenant/haunt3.ogg
Binary file not shown.
Binary file added Resources/Audio/Effects/Revenant/haunt4.ogg
Binary file not shown.
3 changes: 3 additions & 0 deletions Resources/Locale/en-US/alerts/alerts.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ alerts-revenant-essence-desc = The power of souls. It sustains you and is used f
alerts-revenant-corporeal-name = Corporeal
alerts-revenant-corporeal-desc = You have manifested physically. People around you can see and hurt you.

alerts-revenant-essence-regen-name = Haunting
alerts-revenant-essence-regen-desc = You are haunting the crew! You have a boosted essence regeneration rate based on how many people you haunted.

alerts-changeling-chemicals-name = Chemicals
alerts-changeling-chemicals-desc = Spend chemicals to use your abilities. Slowly regenerates.

Expand Down
13 changes: 13 additions & 0 deletions Resources/Prototypes/Actions/revenant.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@
icon: Interface/Actions/shop.png
event: !type:RevenantShopActionEvent

- type: entity
id: ActionRevenantHaunt
name: Haunt
description: Gives essence and stolen essence for every witness.
components:
- type: InstantAction
itemIconStyle: NoItem
icon:
sprite: Mobs/Ghosts/revenant.rsi
state: icon
event: !type:RevenantHauntActionEvent
useDelay: 15

- type: entity
id: ActionRevenantDefile
name: Defile
Expand Down
18 changes: 18 additions & 0 deletions Resources/Prototypes/Alerts/revenant.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
name: alerts-revenant-corporeal-name
description: alerts-revenant-corporeal-desc

- type: alert
id: EssenceRegen
name: alerts-revenant-essence-regen-name
description: alerts-revenant-essence-regen-desc
icons: [ /Textures/Interface/Actions/scream.png ]
alertViewEntity: AlertEssenceRegenSpriteView

- type: alert
id: Stasis
icons:
Expand All @@ -35,3 +42,14 @@
offset: 0.125, 0
- map: [ "enum.RevenantVisualLayers.Digit3" ]
offset: 0.25, 0

- type: entity
id: AlertEssenceRegenSpriteView
components:
- type: Sprite
sprite: /Textures/Interface/Alerts/essence_counter.rsi
layers:
- map: [ "enum.AlertVisualLayers.Base" ]
- map: [ "enum.RevenantVisualLayers.Digit1" ]
- map: [ "enum.RevenantVisualLayers.Digit2" ]
offset: 0.125, 0
Loading
Loading