diff --git a/Content.Server/EntityEffects/Effects/ArtifactUnlock.cs b/Content.Server/EntityEffects/Effects/ArtifactUnlock.cs new file mode 100644 index 0000000000..21454ff7a7 --- /dev/null +++ b/Content.Server/EntityEffects/Effects/ArtifactUnlock.cs @@ -0,0 +1,47 @@ +using Content.Server.Popups; +using Content.Server.Xenoarchaeology.Artifact; +using Content.Shared.EntityEffects; +using Content.Shared.Popups; +using Content.Shared.Xenoarchaeology.Artifact.Components; +using JetBrains.Annotations; +using Robust.Shared.Prototypes; + +namespace Content.Server.EntityEffects.Effects; + +/// +/// Sets an artifact into the unlocking state and marks the artifexium effect as true. +/// This is a very specific behavior intended for a specific chem. +/// +[UsedImplicitly] +public sealed partial class ArtifactUnlock : EntityEffect +{ + public override void Effect(EntityEffectBaseArgs args) + { + var entMan = args.EntityManager; + var xenoArtifactSys = entMan.System(); + var popupSys = entMan.System(); + + if (!entMan.TryGetComponent(args.TargetEntity, out var xenoArtifact)) + return; + + if (!entMan.TryGetComponent(args.TargetEntity, out var unlocking)) + { + xenoArtifactSys.TriggerXenoArtifact((args.TargetEntity, xenoArtifact), null, force: true); + unlocking = entMan.EnsureComponent(args.TargetEntity); + } + else if (!unlocking.ArtifexiumApplied) + { + popupSys.PopupEntity(Loc.GetString("artifact-activation-artifexium"), args.TargetEntity, PopupType.Medium); + } + + if (unlocking.ArtifexiumApplied) + return; + + xenoArtifactSys.SetArtifexiumApplied((args.TargetEntity, unlocking), true); + } + + protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + return Loc.GetString("reagent-effect-guidebook-artifact-unlock", ("chance", Probability)); + } +} diff --git a/Content.Shared/Xenoarchaeology/Artifact/Components/XenoArtifactUnlockingComponent.cs b/Content.Shared/Xenoarchaeology/Artifact/Components/XenoArtifactUnlockingComponent.cs index 13b07f4474..6b2351cc2f 100644 --- a/Content.Shared/Xenoarchaeology/Artifact/Components/XenoArtifactUnlockingComponent.cs +++ b/Content.Shared/Xenoarchaeology/Artifact/Components/XenoArtifactUnlockingComponent.cs @@ -21,6 +21,12 @@ public sealed partial class XenoArtifactUnlockingComponent : Component [DataField, AutoNetworkedField, AutoPausedField] public TimeSpan EndTime; + /// + /// Tracks if artifexium has been applied, which changes the unlock behavior slightly. + /// + [DataField, AutoNetworkedField] + public bool ArtifexiumApplied; + /// /// The sound that plays when an artifact finishes unlocking successfully (with node unlocked). /// diff --git a/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Unlock.cs b/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Unlock.cs index 9786e65478..57d6502bfb 100644 --- a/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Unlock.cs +++ b/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.Unlock.cs @@ -3,6 +3,8 @@ using System.Linq; using Content.Shared.Xenoarchaeology.Artifact.Components; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; +using Robust.Shared.Collections; +using Robust.Shared.Random; namespace Content.Shared.Xenoarchaeology.Artifact; @@ -94,14 +96,14 @@ public abstract partial class SharedXenoArtifactSystem } RemComp(ent, unlockingComponent); - RiseUnlockingFinished(ent, node); + RaiseUnlockingFinished(ent, node); artifactComponent.NextUnlockTime = _timing.CurTime + artifactComponent.UnlockStateRefractory; } public void CancelUnlockingState(Entity ent) { RemComp(ent, ent.Comp1); - RiseUnlockingFinished(ent, null); + RaiseUnlockingFinished(ent, null); } /// @@ -113,9 +115,10 @@ public abstract partial class SharedXenoArtifactSystem ) { node = null; + var potentialNodes = new ValueList>(); var artifactUnlockingComponent = ent.Comp1; - foreach (var nodeIndex in artifactUnlockingComponent.TriggeredNodeIndexes) + foreach (var nodeIndex in GetAllNodeIndices((ent, ent))) { var artifactComponent = ent.Comp2; var curNode = GetNode((ent, artifactComponent), nodeIndex); @@ -125,15 +128,29 @@ public abstract partial class SharedXenoArtifactSystem var requiredIndices = GetPredecessorNodes((ent, artifactComponent), nodeIndex); requiredIndices.Add(nodeIndex); - // Make sure the two sets are identical - if (requiredIndices.Count != artifactUnlockingComponent.TriggeredNodeIndexes.Count - || !artifactUnlockingComponent.TriggeredNodeIndexes.All(requiredIndices.Contains)) + if (!ent.Comp1.ArtifexiumApplied) + { + // Make sure the two sets are identical + if (requiredIndices.Count != artifactUnlockingComponent.TriggeredNodeIndexes.Count + || !artifactUnlockingComponent.TriggeredNodeIndexes.All(requiredIndices.Contains)) + continue; + + node = curNode; + return true; // exit early + } + + // If we apply artifexium, check that the sets are identical EXCEPT for one extra node. + // This node is a "wildcard" and we'll make a pool so we can pick one to actually unlock. + if (!artifactUnlockingComponent.TriggeredNodeIndexes.All(requiredIndices.Contains) || + requiredIndices.Count - 1 != artifactUnlockingComponent.TriggeredNodeIndexes.Count) continue; - node = curNode; - return true; + potentialNodes.Add(curNode); } + if (potentialNodes.Count != 0) + node = RobustRandom.Pick(potentialNodes); + return node != null; } @@ -143,7 +160,7 @@ public abstract partial class SharedXenoArtifactSystem RaiseLocalEvent(ent.Owner, ref unlockingStartedEvent); } - private void RiseUnlockingFinished( + private void RaiseUnlockingFinished( Entity ent, Entity? node ) diff --git a/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.XAT.cs b/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.XAT.cs index 863f56134b..1ef85db27f 100644 --- a/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.XAT.cs +++ b/Content.Shared/Xenoarchaeology/Artifact/SharedXenoArtifactSystem.XAT.cs @@ -56,15 +56,13 @@ public abstract partial class SharedXenoArtifactSystem /// /// 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) + 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 (_timing.CurTime < ent.Comp.NextUnlockTime) + if (!force && _timing.CurTime < ent.Comp.NextUnlockTime) return; - var index = GetIndex(ent, node); - if (!_unlockingQuery.TryGetComponent(ent, out var unlockingComp)) { unlockingComp = EnsureComp(ent); @@ -73,25 +71,34 @@ public abstract partial class SharedXenoArtifactSystem if (_net.IsServer) _popup.PopupEntity(Loc.GetString("artifact-unlock-state-begin"), ent); + Dirty(ent); } - else + 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) + 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 (unlockingComp.TriggeredNodeIndexes.Add(index)) + 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); + } } /// diff --git a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl index 098403c84c..2a40d00f72 100644 --- a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl +++ b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl @@ -357,6 +357,12 @@ reagent-effect-guidebook-add-to-solution-reaction = *[other] cause } chemicals applied to an object to be added to its internal solution container +reagent-effect-guidebook-artifact-unlock = + { $chance -> + [1] Helps + *[other] help + } unlock an alien artifact. + reagent-effect-guidebook-plant-attribute = { $chance -> [1] Adjusts diff --git a/Resources/Locale/en-US/xenoarchaeology/artifact-component.ftl b/Resources/Locale/en-US/xenoarchaeology/artifact-component.ftl index b083d33f35..50fa136928 100644 --- a/Resources/Locale/en-US/xenoarchaeology/artifact-component.ftl +++ b/Resources/Locale/en-US/xenoarchaeology/artifact-component.ftl @@ -15,6 +15,7 @@ artifact-unlock-state-end-failure = It slows down before uneventfully stopping. ### Activation artifact-activation-fail = Nothing happens... +artifact-activation-artifexium = The liquid seeps into the pores of the artifact... ### Misc. artifact-examine-trigger-desc = [color=gray][italic]Am I on your mind?[/italic][/color] diff --git a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/xenoartifacts.yml b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/xenoartifacts.yml index 74a78cee59..6fa30b7265 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/xenoartifacts.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/xenoartifacts.yml @@ -45,6 +45,10 @@ # These components are needed for certain triggers to work. - type: RadiationReceiver - type: Reactive + groups: + Flammable: [Touch] + Extinguish: [Touch] + Acidic: [Touch] - type: entity id: ActionArtifactActivate diff --git a/Resources/Prototypes/Reagents/chemicals.yml b/Resources/Prototypes/Reagents/chemicals.yml index be5473fb8c..85f518bf5e 100644 --- a/Resources/Prototypes/Reagents/chemicals.yml +++ b/Resources/Prototypes/Reagents/chemicals.yml @@ -72,6 +72,14 @@ damage: types: Caustic: 2 + reactiveEffects: + Acidic: + methods: [ Touch ] + effects: + - !type:ArtifactUnlock + conditions: + - !type:ReagentThreshold + min: 5 - type: reagent id: Benzene