[Sci] Non-destructive XenoArch Research (#15398)
* Non-destructive XenoArch research * nerf the price * Points -> Extract
This commit is contained in:
@@ -35,7 +35,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedAmbientSoundSystem _ambienntSound = default!;
|
||||
[Dependency] private readonly SharedAmbientSoundSystem _ambientSound = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
[Dependency] private readonly ArtifactSystem _artifact = default!;
|
||||
@@ -199,6 +199,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
var totalTime = TimeSpan.Zero;
|
||||
var canScan = false;
|
||||
var canPrint = false;
|
||||
var points = 0;
|
||||
if (component.AnalyzerEntity != null && TryComp<ArtifactAnalyzerComponent>(component.AnalyzerEntity, out var analyzer))
|
||||
{
|
||||
artifact = analyzer.LastAnalyzedArtifact;
|
||||
@@ -206,6 +207,10 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
totalTime = analyzer.AnalysisDuration * analyzer.AnalysisDurationMulitplier;
|
||||
canScan = analyzer.Contacts.Any();
|
||||
canPrint = analyzer.ReadyToPrint;
|
||||
|
||||
// the artifact that's actually on the scanner right now.
|
||||
if (GetArtifactForAnalysis(component.AnalyzerEntity, analyzer) is { } current)
|
||||
points = _artifact.GetResearchPointValue(current);
|
||||
}
|
||||
var analyzerConnected = component.AnalyzerEntity != null;
|
||||
var serverConnected = TryComp<ResearchClientComponent>(uid, out var client) && client.ConnectedToServer;
|
||||
@@ -214,7 +219,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
var remaining = active != null ? _timing.CurTime - active.StartTime : TimeSpan.Zero;
|
||||
|
||||
var state = new AnalysisConsoleScanUpdateState(artifact, analyzerConnected, serverConnected,
|
||||
canScan, canPrint, msg, scanning, remaining, totalTime);
|
||||
canScan, canPrint, msg, scanning, remaining, totalTime, points);
|
||||
|
||||
var bui = _ui.GetUi(uid, ArtifactAnalzyerUiKey.Key);
|
||||
_ui.SetUiState(bui, state);
|
||||
@@ -347,22 +352,21 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
if (!_research.TryGetClientServer(uid, out var server, out var serverComponent))
|
||||
return;
|
||||
|
||||
var entToDestroy = GetArtifactForAnalysis(component.AnalyzerEntity);
|
||||
if (entToDestroy == null)
|
||||
var artifact = GetArtifactForAnalysis(component.AnalyzerEntity);
|
||||
if (artifact == null)
|
||||
return;
|
||||
|
||||
if (TryComp<ArtifactAnalyzerComponent>(component.AnalyzerEntity.Value, out var analyzer) &&
|
||||
analyzer.LastAnalyzedArtifact == entToDestroy)
|
||||
{
|
||||
ResetAnalyzer(component.AnalyzerEntity.Value);
|
||||
}
|
||||
var pointValue = _artifact.GetResearchPointValue(artifact.Value);
|
||||
|
||||
_research.AddPointsToServer(server.Value, _artifact.GetResearchPointValue(entToDestroy.Value), serverComponent);
|
||||
EntityManager.DeleteEntity(entToDestroy.Value);
|
||||
if (pointValue == 0)
|
||||
return;
|
||||
|
||||
_research.AddPointsToServer(server.Value, pointValue, serverComponent);
|
||||
_artifact.AdjustConsumedPoints(artifact.Value, pointValue);
|
||||
|
||||
_audio.PlayPvs(component.DestroySound, component.AnalyzerEntity.Value, AudioParams.Default.WithVolume(2f));
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("analyzer-artifact-destroy-popup"),
|
||||
_popup.PopupEntity(Loc.GetString("analyzer-artifact-extract-popup"),
|
||||
component.AnalyzerEntity.Value, PopupType.Large);
|
||||
|
||||
UpdateUserInterface(uid, component);
|
||||
@@ -371,9 +375,6 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Cancels scans if the artifact changes nodes (is activated) during the scan.
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="args"></param>
|
||||
private void OnArtifactActivated(EntityUid uid, ActiveScannedArtifactComponent component, ArtifactActivatedEvent args)
|
||||
{
|
||||
CancelScan(uid);
|
||||
@@ -382,9 +383,6 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Checks to make sure that the currently scanned artifact isn't moved off of the scanner
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="args"></param>
|
||||
private void OnScannedMoved(EntityUid uid, ActiveScannedArtifactComponent component, ref MoveEvent args)
|
||||
{
|
||||
if (!TryComp<ArtifactAnalyzerComponent>(component.Scanner, out var analyzer))
|
||||
@@ -399,9 +397,6 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Stops the current scan
|
||||
/// </summary>
|
||||
/// <param name="artifact">The artifact being scanned</param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="analyzer">The artifact analyzer component</param>
|
||||
[PublicAPI]
|
||||
public void CancelScan(EntityUid artifact, ActiveScannedArtifactComponent? component = null, ArtifactAnalyzerComponent? analyzer = null)
|
||||
{
|
||||
@@ -423,9 +418,6 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Finishes the current scan.
|
||||
/// </summary>
|
||||
/// <param name="uid">The analyzer that is scanning</param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="active"></param>
|
||||
[PublicAPI]
|
||||
public void FinishScan(EntityUid uid, ArtifactAnalyzerComponent? component = null, ActiveArtifactAnalyzerComponent? active = null)
|
||||
{
|
||||
@@ -485,7 +477,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
if (TryComp<ApcPowerReceiverComponent>(uid, out var powa))
|
||||
powa.NeedsPower = true;
|
||||
|
||||
_ambienntSound.SetAmbience(uid, true);
|
||||
_ambientSound.SetAmbience(uid, true);
|
||||
}
|
||||
|
||||
private void OnAnalyzeEnd(EntityUid uid, ActiveArtifactAnalyzerComponent component, ComponentShutdown args)
|
||||
@@ -493,7 +485,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem
|
||||
if (TryComp<ApcPowerReceiverComponent>(uid, out var powa))
|
||||
powa.NeedsPower = false;
|
||||
|
||||
_ambienntSound.SetAmbience(uid, false);
|
||||
_ambientSound.SetAmbience(uid, false);
|
||||
}
|
||||
|
||||
private void OnPowerChanged(EntityUid uid, ActiveArtifactAnalyzerComponent component, ref PowerChangedEvent args)
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace Content.Server.Xenoarchaeology.Equipment.Systems;
|
||||
|
||||
public sealed class SuppressArtifactContainerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ArtifactSystem _artifact = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -15,17 +17,17 @@ public sealed class SuppressArtifactContainerSystem : EntitySystem
|
||||
|
||||
private void OnInserted(EntityUid uid, SuppressArtifactContainerComponent component, EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (!TryComp(args.Entity, out ArtifactComponent? artifact))
|
||||
if (!TryComp<ArtifactComponent>(args.Entity, out var artifact))
|
||||
return;
|
||||
|
||||
artifact.IsSuppressed = true;
|
||||
_artifact.SetIsSuppressed(args.Entity, true, artifact);
|
||||
}
|
||||
|
||||
private void OnRemoved(EntityUid uid, SuppressArtifactContainerComponent component, EntRemovedFromContainerMessage args)
|
||||
{
|
||||
if (!TryComp(args.Entity, out ArtifactComponent? artifact))
|
||||
if (!TryComp<ArtifactComponent>(args.Entity, out var artifact))
|
||||
return;
|
||||
|
||||
artifact.IsSuppressed = false;
|
||||
_artifact.SetIsSuppressed(args.Entity, false, artifact);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
|
||||
|
||||
namespace Content.Server.Xenoarchaeology.XenoArtifacts;
|
||||
|
||||
[RegisterComponent]
|
||||
[RegisterComponent, Access(typeof(ArtifactSystem))]
|
||||
public sealed class ArtifactComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
@@ -53,22 +53,29 @@ public sealed class ArtifactComponent : Component
|
||||
public TimeSpan LastActivationTime;
|
||||
|
||||
/// <summary>
|
||||
/// The base price of each node for an artifact
|
||||
/// A multiplier applied to the calculated point value
|
||||
/// to determine the monetary value of the artifact
|
||||
/// </summary>
|
||||
[DataField("pricePerNode")]
|
||||
public int PricePerNode = 500;
|
||||
[DataField("priceMultiplier"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float PriceMultiplier = 0.05f;
|
||||
|
||||
/// <summary>
|
||||
/// The base amount of research points for each artifact node.
|
||||
/// </summary>
|
||||
[DataField("pointsPerNode")]
|
||||
[DataField("pointsPerNode"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public int PointsPerNode = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Research points which have been "consumed" from the theoretical max value of the artifact.
|
||||
/// </summary>
|
||||
[DataField("consumedPoints"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public int ConsumedPoints;
|
||||
|
||||
/// <summary>
|
||||
/// A multiplier that is raised to the power of the average depth of a node.
|
||||
/// Used for calculating the research point value of an artifact node.
|
||||
/// </summary>
|
||||
[DataField("pointDangerMultiplier")]
|
||||
[DataField("pointDangerMultiplier"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float PointDangerMultiplier = 1.35f;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,29 +51,7 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
/// </remarks>
|
||||
private void GetPrice(EntityUid uid, ArtifactComponent component, ref PriceCalculationEvent args)
|
||||
{
|
||||
var price = component.NodeTree.Sum(x => GetNodePrice(x, component));
|
||||
|
||||
// 25% bonus for fully exploring every node.
|
||||
var fullyExploredBonus = component.NodeTree.Any(x => !x.Triggered) ? 1 : 1.25f;
|
||||
|
||||
args.Price =+ price * fullyExploredBonus;
|
||||
}
|
||||
|
||||
private float GetNodePrice(ArtifactNode node, ArtifactComponent component)
|
||||
{
|
||||
if (!node.Discovered) //no money for undiscovered nodes.
|
||||
return 0;
|
||||
|
||||
var triggerProto = _prototype.Index<ArtifactTriggerPrototype>(node.Trigger);
|
||||
var effectProto = _prototype.Index<ArtifactEffectPrototype>(node.Effect);
|
||||
|
||||
//quarter price if not triggered
|
||||
var priceMultiplier = node.Triggered ? 1f : 0.25f;
|
||||
//the danger is the average of node depth, effect danger, and trigger danger.
|
||||
var nodeDanger = (node.Depth + effectProto.TargetDepth + triggerProto.TargetDepth) / 3;
|
||||
|
||||
var price = MathF.Pow(2f, nodeDanger) * component.PricePerNode * priceMultiplier;
|
||||
return price;
|
||||
args.Price =+ GetResearchPointValue(uid, component) * component.PriceMultiplier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -96,9 +74,32 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
|
||||
var sumValue = component.NodeTree.Sum(n => GetNodePointValue(n, component, getMaxPrice));
|
||||
var fullyExploredBonus = component.NodeTree.All(x => x.Triggered) || getMaxPrice ? 1.25f : 1;
|
||||
sumValue -= component.ConsumedPoints;
|
||||
|
||||
var pointValue = (int) (sumValue * fullyExploredBonus);
|
||||
return pointValue;
|
||||
return (int) (sumValue * fullyExploredBonus);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts how many points on the artifact have been consumed
|
||||
/// </summary>
|
||||
public void AdjustConsumedPoints(EntityUid uid, int amount, ArtifactComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
component.ConsumedPoints += amount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether or not the artifact is suppressed,
|
||||
/// preventing it from activating
|
||||
/// </summary>
|
||||
public void SetIsSuppressed(EntityUid uid, bool suppressed, ArtifactComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
component.IsSuppressed = suppressed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -201,8 +202,8 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component);
|
||||
|
||||
var allNodes = currentNode.Edges;
|
||||
_sawmill.Debug("artifact", $"our node: {currentNode.Id}");
|
||||
_sawmill.Debug("artifact", $"other nodes: {string.Join(", ", allNodes)}");
|
||||
_sawmill.Debug($"our node: {currentNode.Id}");
|
||||
_sawmill.Debug($"other nodes: {string.Join(", ", allNodes)}");
|
||||
|
||||
if (TryComp<BiasedArtifactComponent>(uid, out var bias) &&
|
||||
TryComp<TraversalDistorterComponent>(bias.Provider, out var trav) &&
|
||||
@@ -225,14 +226,14 @@ public sealed partial class ArtifactSystem : EntitySystem
|
||||
}
|
||||
|
||||
var undiscoveredNodes = allNodes.Where(x => !GetNodeFromId(x, component).Discovered).ToList();
|
||||
_sawmill.Debug("artifact", $"Undiscovered nodes: {string.Join(", ", undiscoveredNodes)}");
|
||||
_sawmill.Debug($"Undiscovered nodes: {string.Join(", ", undiscoveredNodes)}");
|
||||
var newNode = _random.Pick(allNodes);
|
||||
if (undiscoveredNodes.Any() && _random.Prob(0.75f))
|
||||
{
|
||||
newNode = _random.Pick(undiscoveredNodes);
|
||||
}
|
||||
|
||||
_sawmill.Debug("artifact", $"Going to node {newNode}");
|
||||
_sawmill.Debug($"Going to node {newNode}");
|
||||
return GetNodeFromId(newNode, component);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user