Files
Delta-v/Content.Server/_Impstation/Revenant/EntitySystems/RevenantStasisSystem.cs
T
39a2b652a6 Add 3 abilities to revenant, salt weaknesses, and evil bible interaction (#3063)
* Added the blood writing ability to revenants

(cherry picked from commit 8157d155e1f7a3840992b54475c59031d2a75f25)

* Added the revenant Animate action

(cherry picked from commit 1b53520849a60538598cae641c6e598b1a5d7534)

* Added Animate action sprite and fixed revenant action sprites being small

(cherry picked from commit 5c88ce9b21cf517023cd136ddb8aaa361f72fbfe)

* Revenants in stasis can now be crafted into sentient revenant plushies

Revenants in stasis can now talk

(cherry picked from commit af84083da6e17bb7671d9f00993dc6bcc0b0a583)

* Revenant plushies and ectoplasm now talk with their trapped revenant's name

(cherry picked from commit 855b25aeb7f29ed6ff2dcc0d4ab1e589ae7e2e16)

* Added a yml nerf option in case revenant is too powerful

(cherry picked from commit 6895a5ca929f32267dea1e326aee62302dc151b8)

* Added a yml nerf option in case revenant is too powerful

(cherry picked from commit 6895a5ca929f32267dea1e326aee62302dc151b8)

* Passing over salt ore now reveals revenants

(cherry picked from commit beea55885f98adc72e34751ba6f798bfadd8dd31)

* Salt puddles now reveal revenants

Hooray for EnsureTileReaction!

(cherry picked from commit b69304747e3b5aa867c5afd8917d2c170c65253e)

* Bibles now reveal revenants

Localization strings added

(cherry picked from commit 62f7ec604748697e5fecc942c4a5d14ff682c596)

* Added the revenant Haunt action

(cherry picked from commit fb692c4cab3f411c11a3004fa73f30122e0ff7f9)

* Haunt witnesses now have an icon over their head on the revenant's client

(cherry picked from commit 5d1b3c6b0af4508ebee7aa8738f7a5f3aa9e53ca)

* Slight revenant nerfs and an additional escape hatch

(cherry picked from commit 490e4c525b75b03502497bfa89827f915f6c7fb2)

* Fixed revenant speech name, and other fixes

This is a few changes clumped into one. I should've broken this one up, but I got overzealous.
- Revenant's ectoplasm now properly uses TransformSpeakerNameEvent
- Revenants crafted into plushies now use VoiceOverrideComponent instead of VoiceMaskComponent
- Plushies now have a custom speaking noise
- Moved Impstation-specific revenant code to the _Impstation subdirectory

(cherry picked from commit a5e0b0c9383e4011e69edc0592c8a4cf40b06402)

* Fixed revenant haunt witness sprite not disappearing

(cherry picked from commit 0c06d4a8f48f6eee324cd944dbcb1fce3258eb58)

* New artifact effectr: animate nearby items (like a revenant)

(cherry picked from commit 6ba1b4d8b313eda9e5ff82246ed7425e80287d0f)

* Revenant cleanups

* Revenant Fixes

* add audio

* haunt fixes

* salt fixes

* grinder gamer

* stasis

* cleanup and comments

* deltav ectoplasm

* clean up imp comment

* event weight and guidebook gaming

* catalog

* alert fix

* window nerf

* effectprobfake

* mapinit

* no braincells ops

Signed-off-by: Lyndomen <49795619+Lyndomen@users.noreply.github.com>

* add physics

* remove phyiscs

* add physics realer

* bible

---------

Signed-off-by: Lyndomen <49795619+Lyndomen@users.noreply.github.com>
Co-authored-by: TGRCDev <tgrc@tgrc.dev>
Co-authored-by: TheGrimbeeper <thegrimbeeper.11@gmail.com>
2025-03-19 16:15:29 +00:00

211 lines
8.2 KiB
C#

using Content.Server.Bible;
using Content.Server.Bible.Components;
using Content.Server.Construction;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Ghost.Roles;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Kitchen.EntitySystems;
using Content.Server.Mind;
using Content.Server.Revenant.Components;
using Content.Server.Speech.Components;
using Content.Shared.Alert;
using Content.Shared.Chat;
using Content.Shared.DoAfter;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Movement.Components;
using Content.Shared.Popups;
using Content.Shared.Revenant;
using Content.Shared.Speech;
using Content.Shared.StatusEffect;
using Content.Shared.Tag;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Server.Revenant.EntitySystems;
public sealed partial class RevenantStasisSystem : EntitySystem
{
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly GhostRoleSystem _ghostRoles = default!;
[Dependency] private readonly MetaDataSystem _meta = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly TagSystem _tags = default!;
[Dependency] private readonly ExplosionSystem _explosion = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[ValidatePrototypeId<StatusEffectPrototype>]
private const string RevenantStasisId = "Stasis";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RevenantStasisComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<RevenantStasisComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<RevenantStasisComponent, StatusEffectEndedEvent>(OnStatusEnded);
SubscribeLocalEvent<RevenantStasisComponent, ChangeDirectionAttemptEvent>(OnAttemptDirection);
SubscribeLocalEvent<RevenantStasisComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<RevenantStasisComponent, ConstructionConsumedObjectEvent>(OnCrafted);
SubscribeLocalEvent<RevenantStasisComponent, ReagentGrinderSystem.GrindAttemptEvent>(OnGrindAttempt);
SubscribeLocalEvent<RevenantStasisComponent, TransformSpeakerNameEvent>(OnTransformName);
SubscribeLocalEvent<RevenantStasisComponent, AfterInteractUsingEvent>(OnBibleInteract, before: [typeof(BibleSystem)]);
SubscribeLocalEvent<RevenantStasisComponent, ExorciseRevenantDoAfterEvent>(OnExorcise);
}
private void OnStartup(EntityUid uid, RevenantStasisComponent component, ComponentStartup args)
{
EnsureComp<AlertsComponent>(uid);
EnsureComp<StatusEffectsComponent>(uid);
_statusEffects.TryAddStatusEffect(uid, RevenantStasisId, component.StasisDuration, true);
var mover = EnsureComp<InputMoverComponent>(uid);
mover.CanMove = false;
Dirty(uid, mover);
var speech = EnsureComp<SpeechComponent>(uid);
speech.SpeechVerb = "Ghost";
Dirty(uid, speech);
if (TryComp<GhostRoleComponent>(uid, out var ghostRole))
_ghostRoles.UnregisterGhostRole((uid, ghostRole));
}
private void OnTransformName(EntityUid uid, RevenantStasisComponent comp, TransformSpeakerNameEvent args)
{
args.VoiceName = Name(comp.Revenant);
args.SpeechVerb = "Ghost";
}
private void OnShutdown(EntityUid uid, RevenantStasisComponent component, ComponentShutdown args)
{
if (_statusEffects.HasStatusEffect(uid, RevenantStasisId))
{
if (_mind.TryGetMind(uid, out var mindId, out var _))
_mind.TransferTo(mindId, null);
QueueDel(component.Revenant);
}
}
private void OnStatusEnded(EntityUid uid, RevenantStasisComponent component, StatusEffectEndedEvent args)
{
if (args.Key == "Stasis")
{
_transformSystem.SetCoordinates(component.Revenant, Transform(uid).Coordinates);
_transformSystem.AttachToGridOrMap(component.Revenant);
_meta.SetEntityPaused(component.Revenant, false);
if (_mind.TryGetMind(uid, out var mindId, out var _))
_mind.TransferTo(mindId, component.Revenant);
QueueDel(uid);
}
}
private void OnExamine(Entity<RevenantStasisComponent> entity, ref ExaminedEvent args)
{
args.PushMarkup(Loc.GetString("revenant-stasis-regenerating"));
}
private void OnCrafted(EntityUid uid, RevenantStasisComponent comp, ConstructionConsumedObjectEvent args)
{
// Permanently sealed into revenant plushie
EnsureComp<InputMoverComponent>(args.New);
var voice = EnsureComp<VoiceOverrideComponent>(args.New);
voice.SpeechVerbOverride = "Ghost";
voice.NameOverride = Name(comp.Revenant);
if (_mind.TryGetMind(uid, out var mindId, out var _))
_mind.TransferTo(mindId, args.New);
}
private void OnGrindAttempt(EntityUid uid, RevenantStasisComponent comp, ReagentGrinderSystem.GrindAttemptEvent args)
{
if (!comp.Revenant.Comp.GrindingRequiresSalt)
return;
foreach (var reagent in args.Reagents)
{
if (_tags.HasAnyTag(reagent, "Salt", "Holy"))
return;
}
// Ripped off the changeling blood explosion variables
_explosion.QueueExplosion(
args.Grinder.Owner,
"Default",
7.5f, // totalIntensity
4f, // slope
2f // maxTileIntensity
);
args.Cancel();
}
private void OnAttemptDirection(EntityUid uid, RevenantStasisComponent comp, ChangeDirectionAttemptEvent args)
{
args.Cancel();
}
private void OnBibleInteract(EntityUid uid, RevenantStasisComponent comp, ref AfterInteractUsingEvent args)
{
if (args.Handled)
return;
if (args.Target == null)
return;
var bible = args.Used;
var target = args.Target.Value;
var user = args.User;
if (!HasComp<BibleComponent>(args.Used))
return;
if (!TryComp<RevenantStasisComponent>(target, out var stasis))
return;
var revenant = stasis.Revenant;
if (revenant.Comp.ExorcismRequiresBibleUser && !HasComp<BibleUserComponent>(args.User))
{
_popup.PopupEntity(Loc.GetString("revenant-exorcise-fail", ("bible", bible)), user, user);
return;
}
var doAfterEventArgs = new DoAfterArgs(EntityManager, user, TimeSpan.FromSeconds(10), new ExorciseRevenantDoAfterEvent(), target, target, bible)
{
BreakOnMove = true,
BreakOnWeightlessMove = false,
BreakOnDamage = true,
NeedHand = true,
DistanceThreshold = 1f
};
if (!_doAfter.TryStartDoAfter(doAfterEventArgs))
return;
args.Handled = true;
_popup.PopupEntity(Loc.GetString("revenant-exorcise-begin-user", [("bible", bible), ("user", user), ("revenant", revenant.Owner)]), user, user);
_popup.PopupEntity(Loc.GetString("revenant-exorcise-begin-target", [("bible", bible), ("user", user), ("revenant", revenant.Owner)]), target, target, PopupType.MediumCaution);
_popup.PopupEntity(Loc.GetString("revenant-exorcise-begin-other", [("bible", bible), ("user", user), ("revenant", revenant.Owner)]), target, Filter.Pvs(target).RemovePlayersByAttachedEntity([user, target]), true);
}
private void OnExorcise(EntityUid uid, RevenantStasisComponent comp, ExorciseRevenantDoAfterEvent args)
{
if (args.Cancelled)
return;
if (args.Target == null || args.Used == null)
return;
var target = args.Target.Value;
var used = args.Used.Value;
_popup.PopupEntity(Loc.GetString("revenant-exorcise-success", [("bible", used), ("user", args.User), ("revenant", comp.Revenant.Owner)]), target);
RemComp<RevenantStasisComponent>(args.Target.Value);
}
}