Anomaly events & science point gen tweaks (#13590)

This commit is contained in:
Nemanja
2023-01-20 19:42:38 -05:00
committed by GitHub
parent f57f9e9ffb
commit cd52b458df
15 changed files with 207 additions and 43 deletions

View File

@@ -74,7 +74,7 @@ public sealed partial class AnomalySystem
UpdateGeneratorUi(uid, component);
}
private void SpawnOnRandomGridLocation(EntityUid grid, string toSpawn)
public void SpawnOnRandomGridLocation(EntityUid grid, string toSpawn)
{
if (!TryComp<MapGridComponent>(grid, out var gridComp))
return;

View File

@@ -95,7 +95,7 @@ public sealed partial class AnomalySystem
component.TokenSource = null;
Audio.PlayPvs(component.CompleteSound, uid);
_popup.PopupEntity(Loc.GetString("anomaly-scanner-component-scan-complete"), uid);
Popup.PopupEntity(Loc.GetString("anomaly-scanner-component-scan-complete"), uid);
UpdateScannerWithNewAnomaly(uid, args.Anomaly, component);
if (TryComp<ActorComponent>(args.User, out var actor))

View File

@@ -21,6 +21,7 @@ public sealed partial class AnomalySystem
SubscribeLocalEvent<AnomalyVesselComponent, ComponentShutdown>(OnVesselShutdown);
SubscribeLocalEvent<AnomalyVesselComponent, MapInitEvent>(OnVesselMapInit);
SubscribeLocalEvent<AnomalyVesselComponent, RefreshPartsEvent>(OnRefreshParts);
SubscribeLocalEvent<AnomalyVesselComponent, UpgradeExamineEvent>(OnUpgradeExamine);
SubscribeLocalEvent<AnomalyVesselComponent, InteractUsingEvent>(OnVesselInteractUsing);
SubscribeLocalEvent<AnomalyVesselComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<AnomalyVesselComponent, ResearchServerGetPointsPerSecondEvent>(OnVesselGetPointsPerSecond);
@@ -59,6 +60,11 @@ public sealed partial class AnomalySystem
component.PointMultiplier = MathF.Pow(component.PartRatingPointModifier, modifierRating);
}
private void OnUpgradeExamine(EntityUid uid, AnomalyVesselComponent component, UpgradeExamineEvent args)
{
args.AddPercentageUpgrade("anomaly-vessel-component-upgrade-output", component.PointMultiplier);
}
private void OnVesselInteractUsing(EntityUid uid, AnomalyVesselComponent component, InteractUsingEvent args)
{
if (component.Anomaly != null ||
@@ -74,7 +80,7 @@ public sealed partial class AnomalySystem
component.Anomaly = scanner.ScannedAnomaly;
anomalyComponent.ConnectedVessel = uid;
UpdateVesselAppearance(uid, component);
_popup.PopupEntity(Loc.GetString("anomaly-vessel-component-anomaly-assigned"), uid);
Popup.PopupEntity(Loc.GetString("anomaly-vessel-component-anomaly-assigned"), uid);
}
private void OnVesselGetPointsPerSecond(EntityUid uid, AnomalyVesselComponent component, ref ResearchServerGetPointsPerSecondEvent args)

View File

@@ -4,7 +4,6 @@ using Content.Server.Audio;
using Content.Server.DoAfter;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Materials;
using Content.Server.Popups;
using Content.Shared.Anomaly;
using Content.Shared.Anomaly.Components;
using Robust.Server.GameObjects;
@@ -24,7 +23,6 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly ExplosionSystem _explosion = default!;
[Dependency] private readonly MaterialStorageSystem _material = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
@@ -101,9 +99,9 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
var multiplier = 1f;
if (component.Stability > component.GrowthThreshold)
multiplier = 1.25f; //more points for unstable
multiplier = component.GrowingPointMultiplier; //more points for unstable
else if (component.Stability < component.DecayThreshold)
multiplier = 0.75f; //less points if it's dying
multiplier = component.DecayingPointMultiplier; //less points if it's dying
//penalty of up to 50% based on health
multiplier *= MathF.Pow(1.5f, component.Health) - 0.5f;

View File

@@ -0,0 +1,51 @@
using System.Linq;
using Content.Server.Anomaly;
using Content.Server.Station.Components;
using Robust.Shared.Random;
namespace Content.Server.StationEvents.Events;
public sealed class AnomalySpawn : StationEventSystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly AnomalySystem _anomaly = default!;
public override string Prototype => "AnomalySpawn";
public readonly string AnomalySpawnerPrototype = "RandomAnomalySpawner";
public override void Added()
{
base.Added();
var str = Loc.GetString("anomaly-spawn-event-announcement",
("sighting", Loc.GetString($"anomaly-spawn-sighting-{_random.Next(1, 6)}")));
ChatSystem.DispatchGlobalAnnouncement(str, colorOverride: Color.FromHex("#18abf5"));
}
public override void Started()
{
base.Started();
if (StationSystem.Stations.Count == 0)
return; // No stations
var chosenStation = RobustRandom.Pick(StationSystem.Stations.ToList());
if (!TryComp<StationDataComponent>(chosenStation, out var stationData))
return;
EntityUid? grid = null;
foreach (var g in stationData.Grids.Where(HasComp<BecomesStationComponent>))
{
grid = g;
}
if (grid is not { })
return;
var amountToSpawn = Math.Max(1, (int) MathF.Round(GetSeverityModifier() / 2));
for (var i = 0; i < amountToSpawn; i++)
{
_anomaly.SpawnOnRandomGridLocation(grid.Value, AnomalySpawnerPrototype);
}
}
}

View File

@@ -34,13 +34,16 @@ public sealed class BluespaceArtifact : StationEventSystem
public override void Started()
{
base.Started();
var amountToSpawn = Math.Max(1, (int) MathF.Round(GetSeverityModifier() / 1.5f));
for (var i = 0; i < amountToSpawn; i++)
{
if (!TryFindRandomTile(out _, out _, out _, out var coords))
return;
if (!TryFindRandomTile(out _, out _, out _, out var coords))
return;
EntityManager.SpawnEntity(ArtifactSpawnerPrototype, coords);
EntityManager.SpawnEntity(ArtifactFlashPrototype, coords);
EntityManager.SpawnEntity(ArtifactSpawnerPrototype, coords);
EntityManager.SpawnEntity(ArtifactFlashPrototype, coords);
Sawmill.Info($"Spawning random artifact at {coords}");
Sawmill.Info($"Spawning random artifact at {coords}");
}
}
}

View File

@@ -51,6 +51,25 @@ public sealed class ArtifactComponent : Component
/// </summary>
[DataField("lastActivationTime", customTypeSerializer: typeof(TimespanSerializer))]
public TimeSpan LastActivationTime;
/// <summary>
/// The base price of each node for an artifact
/// </summary>
[DataField("pricePerNode")]
public int PricePerNode = 500;
/// <summary>
/// The base amount of research points for each artifact node.
/// </summary>
[DataField("pointsPerNode")]
public int PointsPerNode = 5000;
/// <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")]
public float PointDangerMultiplier = 1.35f;
}
/// <summary>

View File

@@ -17,9 +17,6 @@ public sealed partial class ArtifactSystem : EntitySystem
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IRobustRandom _random = default!;
private const int PricePerNode = 500;
private const int PointsPerNode = 5000;
public override void Initialize()
{
base.Initialize();
@@ -34,7 +31,7 @@ public sealed partial class ArtifactSystem : EntitySystem
private void OnInit(EntityUid uid, ArtifactComponent component, MapInitEvent args)
{
RandomizeArtifact(component);
RandomizeArtifact(uid, component);
}
/// <summary>
@@ -52,7 +49,7 @@ public sealed partial class ArtifactSystem : EntitySystem
if (component.NodeTree == null)
return;
var price = component.NodeTree.AllNodes.Sum(GetNodePrice);
var price = component.NodeTree.AllNodes.Sum(x => GetNodePrice(x, component));
// 25% bonus for fully exploring every node.
var fullyExploredBonus = component.NodeTree.AllNodes.Any(x => !x.Triggered) ? 1 : 1.25f;
@@ -60,7 +57,7 @@ public sealed partial class ArtifactSystem : EntitySystem
args.Price =+ price * fullyExploredBonus;
}
private float GetNodePrice(ArtifactNode node)
private float GetNodePrice(ArtifactNode node, ArtifactComponent component)
{
if (!node.Discovered) //no money for undiscovered nodes.
return 0;
@@ -70,7 +67,7 @@ public sealed partial class ArtifactSystem : EntitySystem
//the danger is the average of node depth, effect danger, and trigger danger.
var nodeDanger = (node.Depth + node.Effect.TargetDepth + node.Trigger.TargetDepth) / 3;
var price = MathF.Pow(2f, nodeDanger) * PricePerNode * priceMultiplier;
var price = MathF.Pow(2f, nodeDanger) * component.PricePerNode * priceMultiplier;
return price;
}
@@ -78,43 +75,52 @@ public sealed partial class ArtifactSystem : EntitySystem
/// Calculates how many research points the artifact is worht
/// </summary>
/// <remarks>
/// Rebalance this shit at some point. Definitely OP.
/// General balancing (for fully unlocked artifacts):
/// Simple (1-2 Nodes): ~10K
/// Medium (5-8 Nodes): ~30-40K
/// Complex (7-12 Nodes): ~60-80K
///
/// Simple artifacts should be enough to unlock a few techs.
/// Medium should get you partway through a tree.
/// Complex should get you through a full tree and then some.
/// </remarks>
public int GetResearchPointValue(EntityUid uid, ArtifactComponent? component = null)
{
if (!Resolve(uid, ref component) || component.NodeTree == null)
return 0;
var sumValue = component.NodeTree.AllNodes.Sum(GetNodePointValue);
var sumValue = component.NodeTree.AllNodes.Sum(n => GetNodePointValue(n, component));
var fullyExploredBonus = component.NodeTree.AllNodes.Any(x => !x.Triggered) ? 1 : 1.25f;
var pointValue = (int) (sumValue * fullyExploredBonus);
return pointValue;
}
private float GetNodePointValue(ArtifactNode node)
/// <summary>
/// Gets the point value for an individual node
/// </summary>
private float GetNodePointValue(ArtifactNode node, ArtifactComponent component)
{
if (!node.Discovered)
return 0;
var valueDeduction = !node.Triggered ? 0.5f : 1;
var valueDeduction = !node.Triggered ? 0.25f : 1;
var nodeDanger = (node.Depth + node.Effect.TargetDepth + node.Trigger.TargetDepth) / 3;
return (nodeDanger+1) * PointsPerNode * valueDeduction;
return component.PointsPerNode * MathF.Pow(component.PointDangerMultiplier, nodeDanger) * valueDeduction;
}
/// <summary>
/// Randomize a given artifact.
/// </summary>
[PublicAPI]
public void RandomizeArtifact(ArtifactComponent component)
public void RandomizeArtifact(EntityUid uid, ArtifactComponent component)
{
var nodeAmount = _random.Next(component.NodesMin, component.NodesMax);
component.NodeTree = new ArtifactTree();
GenerateArtifactNodeTree(component.Owner, ref component.NodeTree, nodeAmount);
EnterNode(component.Owner, ref component.NodeTree.StartNode, component);
GenerateArtifactNodeTree(uid, ref component.NodeTree, nodeAmount);
EnterNode(uid, ref component.NodeTree.StartNode, component);
}
/// <summary>
@@ -166,21 +172,21 @@ public sealed partial class ArtifactSystem : EntitySystem
component.CurrentNode.Triggered = true;
if (component.CurrentNode.Edges.Any())
{
var newNode = GetNewNode(component);
var newNode = GetNewNode(uid, component);
if (newNode == null)
return;
EnterNode(uid, ref newNode, component);
}
}
private ArtifactNode? GetNewNode(ArtifactComponent component)
private ArtifactNode? GetNewNode(EntityUid uid, ArtifactComponent component)
{
if (component.CurrentNode == null)
return null;
var allNodes = component.CurrentNode.Edges;
if (TryComp<BiasedArtifactComponent>(component.Owner, out var bias) &&
if (TryComp<BiasedArtifactComponent>(uid, out var bias) &&
TryComp<TraversalDistorterComponent>(bias.Provider, out var trav) &&
_random.Prob(trav.BiasChance) &&
this.IsPowered(bias.Provider, EntityManager))