using Content.Shared.Abilities.Psionics; using Content.Shared.StatusEffect; using Content.Shared.Mobs; using Content.Shared.Psionics.Glimmer; using Content.Shared.Weapons.Melee.Events; using Content.Shared.Damage.Events; using Content.Shared._DV.CCVars; using Content.Shared.IdentityManagement; using Content.Server.Abilities.Psionics; using Content.Server.Chat.Systems; using Content.Server.Electrocution; using Content.Server.NPC.Components; using Content.Server.NPC.Systems; using Content.Shared.NPC.Components; using Content.Shared.NPC.Systems; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Player; using Robust.Shared.Configuration; using Robust.Shared.Random; using Content.Shared._DV.Abilities.Psionics; namespace Content.Server.Psionics { public sealed class PsionicsSystem : EntitySystem { [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly PsionicAbilitiesSystem _psionicAbilitiesSystem = default!; [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; [Dependency] private readonly ElectrocutionSystem _electrocutionSystem = default!; [Dependency] private readonly MindSwapPowerSystem _mindSwapPowerSystem = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly NpcFactionSystem _faction = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; /// /// Unfortunately, since spawning as a normal role and anything else is so different, /// this is the only way to unify them, for now at least. /// Queue<(PotentialPsionicComponent component, EntityUid uid)> _rollers = new(); public override void Update(float frameTime) { base.Update(frameTime); foreach (var roller in _rollers) { RollPsionics(roller.uid, roller.component, false); } _rollers.Clear(); } public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnMeleeHit); SubscribeLocalEvent(OnStamHit); SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnRemove); } private void OnStartup(EntityUid uid, PotentialPsionicComponent component, MapInitEvent args) { if (HasComp(uid)) return; _rollers.Enqueue((component, uid)); } private void OnMeleeHit(EntityUid uid, AntiPsionicWeaponComponent component, MeleeHitEvent args) { foreach (var entity in args.HitEntities) { if (HasComp(entity)) { _audio.PlayPvs("/Audio/Effects/lightburn.ogg", entity); args.ModifiersList.Add(component.Modifiers); if (_random.Prob(component.DisableChance)) _statusEffects.TryAddStatusEffect(entity, "PsionicsDisabled", TimeSpan.FromSeconds(10), true, "PsionicsDisabled"); } if (TryComp(entity, out var swapped)) { _mindSwapPowerSystem.Swap(entity, swapped.OriginalEntity, true); return; } if (component.Punish && HasComp(entity) && !HasComp(entity) && _random.Prob(0.5f)) _electrocutionSystem.TryDoElectrocution(args.User, null, 20, TimeSpan.FromSeconds(5), false); } } private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit args) { if (!component.Removable) return; if (!TryComp(uid, out var factions)) return; if (_faction.IsMember((uid, factions), "GlimmerMonster")) return; _faction.AddFaction((uid, factions), "PsionicInterloper"); } private void OnRemove(EntityUid uid, PsionicComponent component, ComponentRemove args) { if (!TryComp(uid, out var factions)) return; _faction.RemoveFaction((uid, factions), "PsionicInterloper"); } private void OnStamHit(EntityUid uid, AntiPsionicWeaponComponent component, StaminaMeleeHitEvent args) { var bonus = false; foreach (var stam in args.HitList) { if (HasComp(stam.Entity)) bonus = true; } if (!bonus) return; args.FlatModifier += component.PsychicStaminaDamage; } /// /// Makes the entity psionic if it is possible. /// Ignores rolling and rerolling prevention. /// public bool TryMakePsionic(Entity ent) { if (HasComp(ent)) return false; if (!_cfg.GetCVar(DCCVars.PsionicRollsEnabled)) return false; var warn = CompOrNull(ent)?.Warn ?? true; _psionicAbilitiesSystem.AddPsionics(ent, warn); return true; } public void RollPsionics(EntityUid uid, PotentialPsionicComponent component, bool applyGlimmer = true, float multiplier = 1f) { var chance = component.Chance; if (TryComp(uid, out var bonus)) { chance *= bonus.Multiplier; chance += bonus.FlatBonus; } if (applyGlimmer) chance += ((float) _glimmerSystem.Glimmer / 1000); chance *= multiplier; chance = Math.Clamp(chance, 0, 1); if (_random.Prob(chance)) TryMakePsionic((uid, component)); } public void RerollPsionics(EntityUid uid, PotentialPsionicComponent? psionic = null, float bonusMuliplier = 1f) { if (!Resolve(uid, ref psionic, false)) return; if (psionic.Rerolled) return; RollPsionics(uid, psionic, multiplier: bonusMuliplier); psionic.Rerolled = true; } public void GrantNewPsionicReroll(EntityUid uid, PotentialPsionicComponent? psionic = null) { if (!Resolve(uid, ref psionic, false)) return; psionic.Rerolled = false; } } }