Restore Artifexium Effect (#36595)

* Restore Artifexium

* popup

* small tweaks
This commit is contained in:
Nemanja
2025-04-15 18:49:58 -04:00
committed by GitHub
parent a3b68f7181
commit 83c2fdb619
8 changed files with 114 additions and 18 deletions

View File

@@ -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;
/// <summary>
/// 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.
/// </summary>
[UsedImplicitly]
public sealed partial class ArtifactUnlock : EntityEffect
{
public override void Effect(EntityEffectBaseArgs args)
{
var entMan = args.EntityManager;
var xenoArtifactSys = entMan.System<XenoArtifactSystem>();
var popupSys = entMan.System<PopupSystem>();
if (!entMan.TryGetComponent<XenoArtifactComponent>(args.TargetEntity, out var xenoArtifact))
return;
if (!entMan.TryGetComponent<XenoArtifactUnlockingComponent>(args.TargetEntity, out var unlocking))
{
xenoArtifactSys.TriggerXenoArtifact((args.TargetEntity, xenoArtifact), null, force: true);
unlocking = entMan.EnsureComponent<XenoArtifactUnlockingComponent>(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));
}
}

View File

@@ -21,6 +21,12 @@ public sealed partial class XenoArtifactUnlockingComponent : Component
[DataField, AutoNetworkedField, AutoPausedField] [DataField, AutoNetworkedField, AutoPausedField]
public TimeSpan EndTime; public TimeSpan EndTime;
/// <summary>
/// Tracks if artifexium has been applied, which changes the unlock behavior slightly.
/// </summary>
[DataField, AutoNetworkedField]
public bool ArtifexiumApplied;
/// <summary> /// <summary>
/// The sound that plays when an artifact finishes unlocking successfully (with node unlocked). /// The sound that plays when an artifact finishes unlocking successfully (with node unlocked).
/// </summary> /// </summary>

View File

@@ -3,6 +3,8 @@ using System.Linq;
using Content.Shared.Xenoarchaeology.Artifact.Components; using Content.Shared.Xenoarchaeology.Artifact.Components;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems; using Robust.Shared.Audio.Systems;
using Robust.Shared.Collections;
using Robust.Shared.Random;
namespace Content.Shared.Xenoarchaeology.Artifact; namespace Content.Shared.Xenoarchaeology.Artifact;
@@ -94,14 +96,14 @@ public abstract partial class SharedXenoArtifactSystem
} }
RemComp(ent, unlockingComponent); RemComp(ent, unlockingComponent);
RiseUnlockingFinished(ent, node); RaiseUnlockingFinished(ent, node);
artifactComponent.NextUnlockTime = _timing.CurTime + artifactComponent.UnlockStateRefractory; artifactComponent.NextUnlockTime = _timing.CurTime + artifactComponent.UnlockStateRefractory;
} }
public void CancelUnlockingState(Entity<XenoArtifactUnlockingComponent, XenoArtifactComponent> ent) public void CancelUnlockingState(Entity<XenoArtifactUnlockingComponent, XenoArtifactComponent> ent)
{ {
RemComp(ent, ent.Comp1); RemComp(ent, ent.Comp1);
RiseUnlockingFinished(ent, null); RaiseUnlockingFinished(ent, null);
} }
/// <summary> /// <summary>
@@ -113,9 +115,10 @@ public abstract partial class SharedXenoArtifactSystem
) )
{ {
node = null; node = null;
var potentialNodes = new ValueList<Entity<XenoArtifactNodeComponent>>();
var artifactUnlockingComponent = ent.Comp1; var artifactUnlockingComponent = ent.Comp1;
foreach (var nodeIndex in artifactUnlockingComponent.TriggeredNodeIndexes) foreach (var nodeIndex in GetAllNodeIndices((ent, ent)))
{ {
var artifactComponent = ent.Comp2; var artifactComponent = ent.Comp2;
var curNode = GetNode((ent, artifactComponent), nodeIndex); var curNode = GetNode((ent, artifactComponent), nodeIndex);
@@ -125,15 +128,29 @@ public abstract partial class SharedXenoArtifactSystem
var requiredIndices = GetPredecessorNodes((ent, artifactComponent), nodeIndex); var requiredIndices = GetPredecessorNodes((ent, artifactComponent), nodeIndex);
requiredIndices.Add(nodeIndex); requiredIndices.Add(nodeIndex);
if (!ent.Comp1.ArtifexiumApplied)
{
// Make sure the two sets are identical // Make sure the two sets are identical
if (requiredIndices.Count != artifactUnlockingComponent.TriggeredNodeIndexes.Count if (requiredIndices.Count != artifactUnlockingComponent.TriggeredNodeIndexes.Count
|| !artifactUnlockingComponent.TriggeredNodeIndexes.All(requiredIndices.Contains)) || !artifactUnlockingComponent.TriggeredNodeIndexes.All(requiredIndices.Contains))
continue; continue;
node = curNode; node = curNode;
return true; 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;
potentialNodes.Add(curNode);
}
if (potentialNodes.Count != 0)
node = RobustRandom.Pick(potentialNodes);
return node != null; return node != null;
} }
@@ -143,7 +160,7 @@ public abstract partial class SharedXenoArtifactSystem
RaiseLocalEvent(ent.Owner, ref unlockingStartedEvent); RaiseLocalEvent(ent.Owner, ref unlockingStartedEvent);
} }
private void RiseUnlockingFinished( private void RaiseUnlockingFinished(
Entity<XenoArtifactUnlockingComponent, XenoArtifactComponent> ent, Entity<XenoArtifactUnlockingComponent, XenoArtifactComponent> ent,
Entity<XenoArtifactNodeComponent>? node Entity<XenoArtifactNodeComponent>? node
) )

View File

@@ -56,15 +56,13 @@ public abstract partial class SharedXenoArtifactSystem
/// <summary> /// <summary>
/// Attempts to shift artifact into unlocking state, in which it is going to listen to interactions, that could trigger nodes. /// Attempts to shift artifact into unlocking state, in which it is going to listen to interactions, that could trigger nodes.
/// </summary> /// </summary>
public void TriggerXenoArtifact(Entity<XenoArtifactComponent> ent, Entity<XenoArtifactNodeComponent> node) public void TriggerXenoArtifact(Entity<XenoArtifactComponent> ent, Entity<XenoArtifactNodeComponent>? node, bool force = false)
{ {
// limits spontaneous chain activations, also prevents spamming every triggering tool to activate nodes // limits spontaneous chain activations, also prevents spamming every triggering tool to activate nodes
// without real knowledge about triggers // without real knowledge about triggers
if (_timing.CurTime < ent.Comp.NextUnlockTime) if (!force && _timing.CurTime < ent.Comp.NextUnlockTime)
return; return;
var index = GetIndex(ent, node);
if (!_unlockingQuery.TryGetComponent(ent, out var unlockingComp)) if (!_unlockingQuery.TryGetComponent(ent, out var unlockingComp))
{ {
unlockingComp = EnsureComp<XenoArtifactUnlockingComponent>(ent); unlockingComp = EnsureComp<XenoArtifactUnlockingComponent>(ent);
@@ -73,12 +71,15 @@ public abstract partial class SharedXenoArtifactSystem
if (_net.IsServer) if (_net.IsServer)
_popup.PopupEntity(Loc.GetString("artifact-unlock-state-begin"), ent); _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 predecessorNodeIndices = GetPredecessorNodes((ent, ent), index);
var successorNodeIndices = GetSuccessorNodes((ent, ent), index); var successorNodeIndices = GetSuccessorNodes((ent, ent), index);
if(unlockingComp.TriggeredNodeIndexes.Count == 0 if (unlockingComp.TriggeredNodeIndexes.Count == 0
|| unlockingComp.TriggeredNodeIndexes.All( || unlockingComp.TriggeredNodeIndexes.All(
x => predecessorNodeIndices.Contains(x) || successorNodeIndices.Contains(x) x => predecessorNodeIndices.Contains(x) || successorNodeIndices.Contains(x)
) )
@@ -87,11 +88,17 @@ public abstract partial class SharedXenoArtifactSystem
unlockingComp.EndTime += ent.Comp.UnlockStateIncrementPerNode; unlockingComp.EndTime += ent.Comp.UnlockStateIncrementPerNode;
} }
if (unlockingComp.TriggeredNodeIndexes.Add(index)) if (node != null && unlockingComp.TriggeredNodeIndexes.Add(GetIndex(ent, node.Value)))
{ {
Dirty(ent, unlockingComp); Dirty(ent, unlockingComp);
} }
} }
public void SetArtifexiumApplied(Entity<XenoArtifactUnlockingComponent> ent, bool val)
{
ent.Comp.ArtifexiumApplied = val;
Dirty(ent);
}
} }
/// <summary> /// <summary>

View File

@@ -357,6 +357,12 @@ reagent-effect-guidebook-add-to-solution-reaction =
*[other] cause *[other] cause
} chemicals applied to an object to be added to its internal solution container } 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 = reagent-effect-guidebook-plant-attribute =
{ $chance -> { $chance ->
[1] Adjusts [1] Adjusts

View File

@@ -15,6 +15,7 @@ artifact-unlock-state-end-failure = It slows down before uneventfully stopping.
### Activation ### Activation
artifact-activation-fail = Nothing happens... artifact-activation-fail = Nothing happens...
artifact-activation-artifexium = The liquid seeps into the pores of the artifact...
### Misc. ### Misc.
artifact-examine-trigger-desc = [color=gray][italic]Am I on your mind?[/italic][/color] artifact-examine-trigger-desc = [color=gray][italic]Am I on your mind?[/italic][/color]

View File

@@ -45,6 +45,10 @@
# These components are needed for certain triggers to work. # These components are needed for certain triggers to work.
- type: RadiationReceiver - type: RadiationReceiver
- type: Reactive - type: Reactive
groups:
Flammable: [Touch]
Extinguish: [Touch]
Acidic: [Touch]
- type: entity - type: entity
id: ActionArtifactActivate id: ActionArtifactActivate

View File

@@ -72,6 +72,14 @@
damage: damage:
types: types:
Caustic: 2 Caustic: 2
reactiveEffects:
Acidic:
methods: [ Touch ]
effects:
- !type:ArtifactUnlock
conditions:
- !type:ReagentThreshold
min: 5
- type: reagent - type: reagent
id: Benzene id: Benzene