--- /dev/null
+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));
+ }
+}
[DataField, AutoNetworkedField, AutoPausedField]
public TimeSpan EndTime;
+ /// <summary>
+ /// Tracks if artifexium has been applied, which changes the unlock behavior slightly.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool ArtifexiumApplied;
+
/// <summary>
/// The sound that plays when an artifact finishes unlocking successfully (with node unlocked).
/// </summary>
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;
}
RemComp(ent, unlockingComponent);
- RiseUnlockingFinished(ent, node);
+ RaiseUnlockingFinished(ent, node);
artifactComponent.NextUnlockTime = _timing.CurTime + artifactComponent.UnlockStateRefractory;
}
public void CancelUnlockingState(Entity<XenoArtifactUnlockingComponent, XenoArtifactComponent> ent)
{
RemComp(ent, ent.Comp1);
- RiseUnlockingFinished(ent, null);
+ RaiseUnlockingFinished(ent, null);
}
/// <summary>
)
{
node = null;
+ var potentialNodes = new ValueList<Entity<XenoArtifactNodeComponent>>();
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);
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;
}
RaiseLocalEvent(ent.Owner, ref unlockingStartedEvent);
}
- private void RiseUnlockingFinished(
+ private void RaiseUnlockingFinished(
Entity<XenoArtifactUnlockingComponent, XenoArtifactComponent> ent,
Entity<XenoArtifactNodeComponent>? node
)
/// <summary>
/// Attempts to shift artifact into unlocking state, in which it is going to listen to interactions, that could trigger nodes.
/// </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
// 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<XenoArtifactUnlockingComponent>(ent);
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<XenoArtifactUnlockingComponent> ent, bool val)
+ {
+ ent.Comp.ArtifexiumApplied = val;
+ Dirty(ent);
+ }
}
/// <summary>
*[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
### 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]
# These components are needed for certain triggers to work.
- type: RadiationReceiver
- type: Reactive
+ groups:
+ Flammable: [Touch]
+ Extinguish: [Touch]
+ Acidic: [Touch]
- type: entity
id: ActionArtifactActivate
damage:
types:
Caustic: 2
+ reactiveEffects:
+ Acidic:
+ methods: [ Touch ]
+ effects:
+ - !type:ArtifactUnlock
+ conditions:
+ - !type:ReagentThreshold
+ min: 5
- type: reagent
id: Benzene