using Content.Shared.Popups; using Content.Shared.Damage; using Content.Shared.Damage.Components; using Content.Server.Revenant.Components; using Content.Shared.DoAfter; using Content.Shared.Revenant.Components; using Content.Server.NPC.HTN; using Content.Server.NPC; using Content.Shared.Weapons.Melee; using Content.Shared.CombatMode; using Content.Shared.NPC.Components; using Content.Shared.NPC.Systems; using Robust.Shared.Prototypes; using Content.Shared.Damage.Prototypes; using Content.Shared.Movement.Components; using Content.Shared.Item.ItemToggle; using Content.Shared.Item.ItemToggle.Components; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Systems; using Content.Shared.Cuffs.Components; using Content.Shared.Movement.Systems; using Robust.Shared.Player; using Content.Shared.Mind.Components; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Mobs; using Robust.Shared.Timing; using Content.Shared.Construction.Components; using Content.Shared.Trigger.Components; namespace Content.Server.Revenant.EntitySystems; public sealed partial class RevenantAnimatedSystem : EntitySystem { [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly NpcFactionSystem _factionSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly ItemToggleSystem _itemToggleSystem = default!; [Dependency] private readonly SharedGunSystem _gunSystem = default!; [Dependency] private readonly MovementSpeedModifierSystem _moveSpeed = default!; [Dependency] private readonly MobThresholdSystem _thresholds = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnComponentStartup); SubscribeLocalEvent(OnComponentShutdown); SubscribeLocalEvent(OnMobStateChange); } public override void Update(float frameTime) { base.Update(frameTime); var enumerator = EntityQueryEnumerator(); while (enumerator.MoveNext(out var uid, out var animate)) { if (animate.EndTime == null) continue; if (animate.EndTime <= _gameTiming.CurTime) InanimateTarget(uid, animate); } } private void OnComponentStartup(Entity ent, ref ComponentStartup _) { if (ent.Comp.LifeStage != ComponentLifeStage.Starting) return; // Turn on welding rods and stun prods if (HasComp(ent.Owner) && TryComp(ent.Owner, out var toggle)) _itemToggleSystem.TryActivate((ent.Owner, toggle)); _popup.PopupEntity(Loc.GetString("revenant-animate-item-animate", ("target", ent.Owner)), ent.Owner, Filter.Pvs(ent.Owner), true); // Add melee damage if an item doesn't already have it if (EnsureHelper(ent, out var melee)) melee.Damage = new DamageSpecifier(_prototypeManager.Index("Blunt"), 5); EnsureHelper(ent); EnsureHelper(ent, out var moveSpeed); if (ent.Comp.Revenant != null) _moveSpeed.ChangeBaseSpeed(ent, ent.Comp.Revenant.Value.Comp.AnimateWalkSpeed, ent.Comp.Revenant.Value.Comp.AnimateSprintSpeed, MovementSpeedModifierComponent.DefaultAcceleration, moveSpeed ); else _moveSpeed.ChangeBaseSpeed(ent, RevenantComponent.DefaultAnimateWalkSpeed, RevenantComponent.DefaultAnimateSprintSpeed, MovementSpeedModifierComponent.DefaultAcceleration, moveSpeed ); EnsureHelper(ent, out var factions); _factionSystem.ClearFactions((ent, factions)); _factionSystem.AddFaction((ent, factions), "SimpleHostile"); // For things like handcuffs EnsureHelper(ent); EnsureHelper(ent, out var htn); if (HasComp(ent)) { // Goals: Magdump into any nearby creatures, and melee hit them if empty if (ent.Comp.Revenant != null && ent.Comp.Revenant.Value.Comp.AnimateCanBoltGuns && TryComp(ent, out var bolt)) _gunSystem.SetBoltClosed(ent, bolt, true); htn.RootTask = new HTNCompoundTask() { Task = "SimpleRangedHostileCompound" }; } else if (HasComp(ent)) // Goals: Jump into any creature's pockets/hands and cuff them htn.RootTask = new HTNCompoundTask() { Task = "AnimatedHandcuffsCompound" }; else if (HasComp(ent)) // Goals: Jump into any creature's pockets/hands and activate self htn.RootTask = new HTNCompoundTask() { Task = "AnimatedGrenadeCompound" }; else // Goals: Fist fight anyone near you htn.RootTask = new HTNCompoundTask() { Task = "SimpleHostileCompound" }; htn.Blackboard.SetValue(NPCBlackboard.Owner, ent.Owner); EnsureHelper(ent); EnsureHelper(ent); EnsureHelper(ent, out var thresholds); _thresholds.SetMobStateThreshold(ent, 30, MobState.Dead, thresholds); EnsureHelper(ent); } private void OnComponentShutdown(Entity ent, ref ComponentShutdown _) { if (ent.Comp.LifeStage != ComponentLifeStage.Stopping) return; foreach (var comp in ent.Comp.AddedComponents) { if (comp.Deleted) continue; RemCompDeferred(ent, comp); } _popup.PopupEntity(Loc.GetString("revenant-animate-item-inanimate", ("target", ent)), ent, Filter.Pvs(ent), true); } private void OnMobStateChange(Entity ent, ref MobStateChangedEvent args) { if (args.NewMobState == MobState.Dead) { InanimateTarget(ent); } } // Returns true if a new component was added to the target. private bool EnsureHelper(Entity target, out T comp) where T : Component, new() { if (TryComp(target, out var existing)) { comp = existing; return false; } comp = AddComp(target); target.Comp.AddedComponents.Add(comp); return true; } private bool EnsureHelper(Entity target) where T : Component, new() { return EnsureHelper(target, out _); } public bool CanAnimateObject(EntityUid target) { return !(HasComp(target) || HasComp(target) || HasComp(target) || HasComp(target)); } public bool TryAnimateObject(EntityUid target, TimeSpan? duration = null, Entity? revenant = null) { if (!CanAnimateObject(target)) return false; var animate = EnsureComp(target); animate.Revenant = revenant; if (duration != null) animate.EndTime = _gameTiming.CurTime + duration.Value; else if (revenant != null) animate.EndTime = _gameTiming.CurTime + revenant.Value.Comp.AnimateTime; return true; } public void InanimateTarget(EntityUid target, RevenantAnimatedComponent? comp = null) { if (!target.Valid || !Resolve(target, ref comp)) return; RemComp(target); } }