using System.Linq; using Content.Shared.Chemistry; using Content.Shared.Damage; using Content.Shared.Damage.Systems; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Movement.Pulling.Events; using Content.Shared.Throwing; using Content.Shared.Weapons.Melee.Events; using Content.Shared.Xenoarchaeology.Artifact.Components; using Content.Shared.Xenoarchaeology.Artifact.XAT.Components; namespace Content.Shared.Xenoarchaeology.Artifact; public abstract partial class SharedXenoArtifactSystem { private void InitializeXAT() { XATRelayLocalEvent(); XATRelayLocalEvent(); XATRelayLocalEvent(); XATRelayLocalEvent(); XATRelayLocalEvent(); XATRelayLocalEvent(); XATRelayLocalEvent(); XATRelayLocalEvent(); // special case this one because we need to order the messages SubscribeLocalEvent(OnExamined); } /// Relays artifact events for artifact nodes. protected void XATRelayLocalEvent() where T : notnull { SubscribeLocalEvent(RelayEventToNodes); } private void OnExamined(Entity ent, ref ExaminedEvent args) { using (args.PushGroup(nameof(XenoArtifactComponent))) { RelayEventToNodes(ent, ref args); } } protected void RelayEventToNodes(Entity ent, ref T args) where T : notnull { var ev = new XenoArchNodeRelayedEvent(ent, args); var nodes = GetAllNodes(ent); foreach (var node in nodes) { RaiseLocalEvent(node, ref ev); } } /// /// Attempts to shift artifact into unlocking state, in which it is going to listen to interactions, that could trigger nodes. /// public void TriggerXenoArtifact(Entity ent, Entity? node, bool force = false) { // limits spontaneous chain activations, also prevents spamming every triggering tool to activate nodes // without real knowledge about triggers if (!force && _timing.CurTime < ent.Comp.NextUnlockTime) return; if (!_unlockingQuery.TryGetComponent(ent, out var unlockingComp)) { unlockingComp = EnsureComp(ent); unlockingComp.EndTime = _timing.CurTime + ent.Comp.UnlockStateDuration; Log.Debug($"{ToPrettyString(ent)} entered unlocking state"); if (_net.IsServer) _popup.PopupEntity(Loc.GetString("artifact-unlock-state-begin"), ent); Dirty(ent); } else if (node != null) { var index = GetIndex(ent, node.Value); var predecessorNodeIndices = GetPredecessorNodes((ent, ent), index); var successorNodeIndices = GetSuccessorNodes((ent, ent), index); if (unlockingComp.TriggeredNodeIndexes.Count == 0 || unlockingComp.TriggeredNodeIndexes.All( x => predecessorNodeIndices.Contains(x) || successorNodeIndices.Contains(x) ) ) // we add time on each new trigger, if it is not going to fail us unlockingComp.EndTime += ent.Comp.UnlockStateIncrementPerNode; } if (node != null && unlockingComp.TriggeredNodeIndexes.Add(GetIndex(ent, node.Value))) { Dirty(ent, unlockingComp); } } public void SetArtifexiumApplied(Entity ent, bool val) { ent.Comp.ArtifexiumApplied = val; Dirty(ent); } } /// /// Event wrapper for XenoArch Trigger events. /// [ByRefEvent] public record struct XenoArchNodeRelayedEvent(Entity Artifact, TEvent Args) { /// /// Original event. /// public TEvent Args = Args; /// /// Artifact entity, that received original event. /// public Entity Artifact = Artifact; }