Обновление суперматерии (#2732)
|
|
@ -50,6 +50,7 @@ public sealed class LightningSystem : SharedLightningSystem
|
|||
public void ShootLightning(EntityUid user, EntityUid target, string lightningPrototype = "Lightning", bool triggerLightningEvents = true)
|
||||
{
|
||||
var spriteState = LightningRandomizer();
|
||||
|
||||
_beam.TryCreateBeam(user, target, lightningPrototype, spriteState);
|
||||
|
||||
if (triggerLightningEvents) // we don't want certain prototypes to trigger lightning level events
|
||||
|
|
@ -69,7 +70,7 @@ public sealed class LightningSystem : SharedLightningSystem
|
|||
/// <param name="lightningPrototype">The prototype for the lightning to be created</param>
|
||||
/// <param name="arcDepth">how many times to recursively fire lightning bolts from the target points of the first shot.</param>
|
||||
/// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param>
|
||||
public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true)
|
||||
public bool ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true)
|
||||
{
|
||||
//TODO: add support to different priority target tablem for different lightning types
|
||||
//TODO: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
|
||||
|
|
@ -80,6 +81,7 @@ public sealed class LightningSystem : SharedLightningSystem
|
|||
_random.Shuffle(targets);
|
||||
targets.Sort((x, y) => y.Comp.Priority.CompareTo(x.Comp.Priority));
|
||||
|
||||
bool shooted = false; //starlight
|
||||
int shootedCount = 0;
|
||||
int count = -1;
|
||||
while(shootedCount < boltCount)
|
||||
|
|
@ -93,12 +95,14 @@ public sealed class LightningSystem : SharedLightningSystem
|
|||
continue;
|
||||
|
||||
ShootLightning(user, targets[count].Owner, lightningPrototype, triggerLightningEvents);
|
||||
shooted = true;//starlight
|
||||
if (arcDepth - targets[count].Comp.LightningResistance > 0)
|
||||
{
|
||||
ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targets[count].Comp.LightningResistance, triggerLightningEvents);
|
||||
}
|
||||
shootedCount++;
|
||||
}
|
||||
return shooted; //starlight
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ using Content.Server.Singularity.Events;
|
|||
using Content.Shared.Singularity.Components;
|
||||
using Content.Shared.Singularity.EntitySystems;
|
||||
using Content.Shared.Singularity.Events;
|
||||
using Content.Server.Supermatter.Components;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Singularity.EntitySystems;
|
||||
|
|
@ -36,11 +37,6 @@ public sealed class SingularitySystem : SharedSingularitySystem
|
|||
/// </summary>
|
||||
public const float BaseEntityEnergy = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the singuloo has eaten the supermatter crystal
|
||||
/// </summary>
|
||||
public bool HasEatenSM = false;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
|
@ -107,7 +103,7 @@ public sealed class SingularitySystem : SharedSingularitySystem
|
|||
{
|
||||
// Normally, a level 6 singularity requires the supermatter + 3000 energy.
|
||||
// The required amount of energy has been bumped up to compensate for the lack of the supermatter.
|
||||
>= 5000 when HasEatenSM => 6,
|
||||
>= 5000 => 6,
|
||||
>= 2000 => 5,
|
||||
>= 1000 => 4,
|
||||
>= 500 => 3,
|
||||
|
|
@ -220,8 +216,7 @@ public sealed class SingularitySystem : SharedSingularitySystem
|
|||
// Don't double count singulo food
|
||||
if (HasComp<SinguloFoodComponent>(args.Entity))
|
||||
return;
|
||||
if (HasComp<SupermatterComponent>(uid))
|
||||
HasEatenSM = true;
|
||||
|
||||
AdjustEnergy(uid, BaseEntityEnergy, singularity: comp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,276 +0,0 @@
|
|||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server.Supermatter.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class SupermatterComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The damage taken from direct hits, e.g. laser weapons
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float AVExternalDamage = 0f;
|
||||
|
||||
//
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float HeatAccumulatorRate = 0.5f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float AVHeatAccumulator = 0f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float RadiationAccumulatorRate = 0.3f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float AVRadiationAccumulator = 0f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float LightingAccumulatorThreshold = 2f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float LightingAccumulatorRate = 0.1f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float AVLightingAccumulator = 0f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float InternalEnergyAccumulatorRate = 0.1f;
|
||||
/// <summary>
|
||||
/// Lightning prototype IDs that the supermatter should spit out.
|
||||
/// </summary>
|
||||
public readonly string[] LightningPrototypeIDs =
|
||||
{
|
||||
"Lightning",
|
||||
"ChargedLightning",
|
||||
"SuperchargedLightning",
|
||||
"HyperchargedLightning"
|
||||
};
|
||||
public readonly string SliverPrototype = "SupermatterSliver";
|
||||
|
||||
[DataField("zapSound")]
|
||||
public SoundSpecifier SupermatterZapSound = new SoundPathSpecifier("/Audio/Weapons/emitter2.ogg");
|
||||
|
||||
[DataField("calmAmbienceSound")]
|
||||
public SoundSpecifier CalmAmbienceSound = new SoundPathSpecifier("/Audio/Ambience/Objects/supermatter_calm.ogg");
|
||||
|
||||
[DataField("delamAmbienceSound")]
|
||||
public SoundSpecifier DelamAmbienceSound = new SoundPathSpecifier("/Audio/Ambience/Objects/supermatter_delam.ogg");
|
||||
|
||||
[ViewVariables]
|
||||
public SoundSpecifier CurrentAmbience = new SoundPathSpecifier("/Audio/Ambience/Objects/supermatter_calm.ogg");
|
||||
|
||||
[DataField("teslaSpawnPrototype")]
|
||||
public string TeslaPrototype = "TeslaEnergyBall";
|
||||
|
||||
[DataField("singularitySpawnPrototype")]
|
||||
public string SingularityPrototype = "Singularity";
|
||||
|
||||
[DataField("supermatterKudzuSpawnPrototype")]
|
||||
public string SupermatterKudzuPrototype = "SupermatterKudzu";
|
||||
|
||||
/// <summary>
|
||||
/// If a supermatter sliver has been removed. Lowers the delamination countdown time.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool SliverRemoved = false;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether supermatter crystal is active or not.
|
||||
/// </summary>
|
||||
[DataField("activated")]
|
||||
public bool Activated = false;
|
||||
|
||||
[ViewVariables]
|
||||
public GasMixture AbsorbedGasMix = new();
|
||||
|
||||
/// <summary>
|
||||
/// Delta time between Update() calls storage.
|
||||
/// </summary>
|
||||
public float DeltaTime = 0f;
|
||||
|
||||
public float UpdateTimerAccumulator = 0f;
|
||||
|
||||
public float AnnouncementTimerAccumulator = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of seconds to pass before another SM cycle.
|
||||
/// </summary>
|
||||
[DataField("updateTimer")]
|
||||
public float UpdateTimer = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of seconds to pass before makes an announcement.
|
||||
/// </summary>
|
||||
[DataField("announcementTimer")]
|
||||
public float AnnouncementTimer = 60f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int? PreferredDelamType = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The time in seconds for crystal to delaminate.
|
||||
/// </summary>
|
||||
[DataField("countdownTimer")]
|
||||
public float DelamCountdownTimerRaw = 120f;
|
||||
public float DelamCountdownTimer => SliverRemoved ? DelamCountdownTimerRaw / 2 : DelamCountdownTimerRaw;
|
||||
public bool DelamAnnouncementHappened = false;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float DelamCountdownAccumulator = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// The portion of gasmix we should absorb.
|
||||
/// </summary>
|
||||
[DataField("gasAbsorptionRatio")]
|
||||
public float AbsorptionRatio = .15f;
|
||||
|
||||
/// <summary>
|
||||
/// This value effects gas output, damage and power generation.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float InternalEnergy = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of damage the SM currently has.
|
||||
/// </summary>
|
||||
[DataField("damage")]
|
||||
public float Damage = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of damage SM had before the cycle.
|
||||
/// </summary>
|
||||
public float DamageArchive = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// The temperature at which the supermatter crystal will begin to take damage.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float TempLimit = Atmospherics.T0C + HeatPenaltyThreshold;
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies our gas waste amount and temperature.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float WasteMultiplier = 0f;
|
||||
|
||||
[DataField("damageDangerPoint")]
|
||||
public float DamageDangerPoint = 50f;
|
||||
|
||||
[DataField("damageEmergencyPoint")]
|
||||
public float DamageEmergencyPoint = 75f;
|
||||
|
||||
[DataField("damageDelaminationPoint")]
|
||||
public float DelaminationPoint = 100f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool AreWeDelaming = false;
|
||||
|
||||
/// <summary>
|
||||
/// Affects the heat SM makes.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float GasHeatModifier = 0f;
|
||||
/// <summary>
|
||||
/// Affters the minimum point at which SM takes damage.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float GasHeatResistance = 0f;
|
||||
/// <summary>
|
||||
/// How much power decay is negated. Complete power decay negation at 1.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float GasPowerlossInhibition = 0f;
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float ThermalСonductivity = 0f;
|
||||
/// <summary>
|
||||
/// Affects the power gain the SM experiences from heat.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float HeatPowerGeneration = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Lesser than that and it's not worth processing.
|
||||
/// </summary>
|
||||
public const float MinimumMoleCount = .01f;
|
||||
|
||||
public const float HeatPenaltyThreshold = 40f;
|
||||
public const float PowerPenaltyThreshold = 3f;
|
||||
public const float MolePenaltyThreshold = 900f;
|
||||
public const float ThermalReleaseModifier = 4f;
|
||||
public const float PlasmaReleaseModifier = 1.5f;
|
||||
public const float OxygenReleaseModifier = 2.5f;
|
||||
public const float GasHeatPowerScaling = 1f / 6f;
|
||||
|
||||
/// <summary>
|
||||
/// Stores gas properties used for the supermatter.
|
||||
/// Array values should alwayd match gas enum values.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public GasFact[] GasFacts =
|
||||
{
|
||||
new (thermalConductivity: 2.4f, heatPowerGeneration: 1f), // o2
|
||||
new (thermalConductivity: 2.0f, heatModifier: -2.5f, heatPowerGeneration: -1), // n2
|
||||
new (thermalConductivity: 1.2f, heatModifier: 1f, heatPowerGeneration: 1f, powerlossInhibition: 1f), // co2
|
||||
new (thermalConductivity: 6.0f, heatModifier: 14f, heatPowerGeneration: 1f), // plasma
|
||||
new (thermalConductivity: 3.0f, heatModifier: 9f, heatPowerGeneration: 1f), // tritium
|
||||
new (thermalConductivity: 1.4f, heatModifier: 11f, heatPowerGeneration: 1f), // vapor
|
||||
new (thermalConductivity: 1.6f, heatPowerGeneration: .5f), // ommonium
|
||||
new (thermalConductivity: 1.3f, heatResistance: 5f), // n2o
|
||||
new (thermalConductivity: 9.9f, heatModifier: 9f, heatResistance: 1f, heatPowerGeneration: 1f), // frezon
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores gas properties used for the supermatter.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataDefinition]
|
||||
public sealed partial class GasFact
|
||||
{
|
||||
/// <summary>
|
||||
/// Affects the amount of power the main SM zap makes.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float ThermalСonductivity;
|
||||
/// <summary>
|
||||
/// Affects the heat SM makes.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float HeatModifier;
|
||||
/// <summary>
|
||||
/// Affters the minimum point at which SM takes damage.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float HeatResistance;
|
||||
/// <summary>
|
||||
/// Affects the power gain the SM experiences from heat.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float HeatPowerGeneration;
|
||||
/// <summary>
|
||||
/// How much power decay is negated. Complete power decay negation at 1.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float PowerlossInhibition;
|
||||
|
||||
public GasFact(float? thermalConductivity = null, float? heatModifier = null, float? heatResistance = null, float? heatPowerGeneration = null, float? powerlossInhibition = null)
|
||||
{
|
||||
ThermalСonductivity = thermalConductivity ?? 1;
|
||||
HeatModifier = heatModifier ?? 1;
|
||||
HeatResistance = heatResistance ?? 0;
|
||||
HeatPowerGeneration = heatPowerGeneration ?? 0;
|
||||
PowerlossInhibition = powerlossInhibition ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of delamination that should occur.
|
||||
/// </summary>
|
||||
public enum DelamType : sbyte
|
||||
{
|
||||
Explosion = 0,
|
||||
Tesla = 1,
|
||||
Singularity = 2,
|
||||
ResonanceCascade = 3,
|
||||
}
|
||||
|
|
@ -1,504 +0,0 @@
|
|||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Supermatter.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Server.Lightning;
|
||||
using Content.Shared.Radiation.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Server.Audio;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Anomaly;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Supermatter;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Random;
|
||||
using Content.Shared.Database;
|
||||
using Content.Server.Chat.Systems;
|
||||
using System.Text;
|
||||
using Content.Server.AlertLevel;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.Kitchen.Components;
|
||||
using Content.Shared.Weapons.Melee.EnergySword;
|
||||
using Content.Shared.Singularity.Components;
|
||||
using System;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server.Supermatter.EntitySystems;
|
||||
|
||||
public sealed class SupermatterSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AtmosphereSystem _atmos = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _sound = default!;
|
||||
[Dependency] private readonly LightningSystem _lightning = default!;
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly AlertLevelSystem _alert = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly AmbientSoundSystem _ambience = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
[Dependency] private readonly StationSystem _station = default!;
|
||||
[Dependency] private readonly AnomalySystem _anomaly = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly DoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly ExplosionSystem _explosion = default!;
|
||||
|
||||
public static SoundSpecifier VaporizeSound =
|
||||
new SoundPathSpecifier("/Audio/Effects/Grenades/Supermatter/supermatter_start.ogg");
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SupermatterComponent, StartCollideEvent>(OnCollide);
|
||||
SubscribeLocalEvent<SupermatterComponent, InteractUsingEvent>(OnClick);
|
||||
SubscribeLocalEvent<SupermatterComponent, SupermatterDoAfterEvent>(OnGetSliver);
|
||||
SubscribeLocalEvent<SupermatterComponent, DamageChangedEvent>(OnGetHit);
|
||||
SubscribeLocalEvent<SupermatterComponent, ExaminedEvent>(OnExamine);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var sm in EntityQuery<SupermatterComponent>())
|
||||
{
|
||||
if (!sm.Activated)
|
||||
return;
|
||||
|
||||
var uid = sm.Owner;
|
||||
|
||||
sm.DeltaTime = frameTime;
|
||||
sm.UpdateTimerAccumulator += frameTime;
|
||||
|
||||
if (sm.UpdateTimerAccumulator >= sm.UpdateTimer)
|
||||
{
|
||||
sm.UpdateTimerAccumulator = 0f;
|
||||
Cycle(uid, sm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Cycle(EntityUid uid, SupermatterComponent sm)
|
||||
{
|
||||
sm.AnnouncementTimerAccumulator++;
|
||||
|
||||
ProcessAtmos(uid, sm);
|
||||
ProcessPower(uid, sm);
|
||||
ProcessDamage(uid, sm);
|
||||
|
||||
// due to how damage calculation works, it will do the announcement only if sm is consistently taking damage
|
||||
if (sm.Damage > sm.DamageArchive)
|
||||
{
|
||||
if (sm.AnnouncementTimerAccumulator > sm.AnnouncementTimer)
|
||||
{
|
||||
sm.AnnouncementTimerAccumulator = 0f;
|
||||
var loc = "danger";
|
||||
if (sm.Damage > sm.DamageEmergencyPoint)
|
||||
loc = "critical";
|
||||
|
||||
SupermatterAlert(uid, Loc.GetString($"supermatter-announcement-{loc}", ("integrity", (int)(sm.DelaminationPoint - sm.Damage))));
|
||||
}
|
||||
}
|
||||
sm.DamageArchive = sm.Damage;
|
||||
|
||||
if (sm.AreWeDelaming)
|
||||
DelamCountdown(uid, sm);
|
||||
|
||||
ProcessWaste(uid, sm);
|
||||
|
||||
HandleSound(uid, sm);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate power based on gases absorbed.
|
||||
/// </summary>
|
||||
private void ProcessAtmos(EntityUid uid, SupermatterComponent sm)
|
||||
{
|
||||
var mix = _atmos.GetContainingMixture((uid, Transform(uid)), true, true) ?? new();
|
||||
var absorbedMix = mix?.RemoveRatio(sm.AbsorptionRatio) ?? new();
|
||||
|
||||
// calculate gases
|
||||
var gasPercentages = new float[Enum.GetValues(typeof(Gas)).Length];
|
||||
|
||||
var thermalСonductivity = 0f;
|
||||
var heatModifier = 0f;
|
||||
var heatResistance = 0f;
|
||||
var heatPowerGeneration = 0f;
|
||||
var powerlossInhibition = 0f;
|
||||
|
||||
var moles = absorbedMix.TotalMoles;
|
||||
|
||||
if (moles <= SupermatterComponent.MinimumMoleCount)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < gasPercentages.Length; i++)
|
||||
{
|
||||
var moleCount = absorbedMix.GetMoles(i);
|
||||
|
||||
if (moleCount <= SupermatterComponent.MinimumMoleCount)
|
||||
continue;
|
||||
|
||||
gasPercentages[i] = moleCount / moles;
|
||||
var smGas = sm.GasFacts[i];
|
||||
|
||||
thermalСonductivity += smGas.ThermalСonductivity * gasPercentages[i];
|
||||
heatModifier += smGas.HeatModifier * gasPercentages[i];
|
||||
heatResistance += smGas.HeatResistance * gasPercentages[i];
|
||||
heatPowerGeneration += smGas.HeatPowerGeneration * gasPercentages[i];
|
||||
powerlossInhibition += smGas.PowerlossInhibition * gasPercentages[i];
|
||||
}
|
||||
|
||||
heatPowerGeneration = Math.Clamp(heatPowerGeneration, 0, 1);
|
||||
powerlossInhibition = Math.Clamp(powerlossInhibition, 0, 1);
|
||||
|
||||
sm.AbsorbedGasMix = absorbedMix;
|
||||
sm.ThermalСonductivity = thermalСonductivity;
|
||||
sm.GasHeatModifier = heatModifier;
|
||||
sm.GasHeatResistance = heatResistance;
|
||||
sm.HeatPowerGeneration = heatPowerGeneration;
|
||||
sm.GasPowerlossInhibition = powerlossInhibition;
|
||||
}
|
||||
/// <summary>
|
||||
/// Shoot lightning and radiate everything based on whatever power there is.
|
||||
/// </summary>
|
||||
private void ProcessPower(EntityUid uid, SupermatterComponent sm)
|
||||
{
|
||||
var powerHeat = sm.HeatPowerGeneration * sm.AbsorbedGasMix.Temperature * SupermatterComponent.GasHeatPowerScaling;
|
||||
var powerloss = -1 * sm.GasPowerlossInhibition;
|
||||
var atmosStrength = Math.Clamp((powerHeat + powerloss) * 0.2f, 0, 2);
|
||||
|
||||
var damageStrength = Math.Clamp(sm.Damage / sm.DelaminationPoint, 0, 1);
|
||||
var strength = Math.Clamp(atmosStrength + damageStrength, 0, 4);
|
||||
var damageExternal = sm.AVExternalDamage + strength;
|
||||
sm.AVExternalDamage = 0f;
|
||||
|
||||
sm.AVHeatAccumulator = Math.Clamp(sm.AVHeatAccumulator + (damageExternal * sm.HeatAccumulatorRate), 0, 10);
|
||||
sm.AVRadiationAccumulator = Math.Clamp(sm.AVRadiationAccumulator + (damageExternal * sm.RadiationAccumulatorRate), 0, 10);
|
||||
sm.AVLightingAccumulator = Math.Clamp(sm.AVLightingAccumulator + (damageExternal * sm.LightingAccumulatorRate), 0, 10);
|
||||
sm.InternalEnergy = Math.Clamp(sm.InternalEnergy + (damageExternal * sm.InternalEnergyAccumulatorRate), 0, 10);
|
||||
|
||||
if (sm.AVLightingAccumulator > sm.LightingAccumulatorThreshold)
|
||||
{
|
||||
var lightningProto = sm.LightningPrototypeIDs[(int)Math.Clamp(sm.AVLightingAccumulator, 0, 3)];
|
||||
_lightning.ShootRandomLightnings(uid, 3, (int)sm.AVLightingAccumulator, lightningProto);
|
||||
sm.AVLightingAccumulator = 0;
|
||||
}
|
||||
|
||||
Comp<RadiationSourceComponent>(uid).Intensity = 1 + sm.AVRadiationAccumulator;
|
||||
sm.AVRadiationAccumulator /= 2;
|
||||
sm.InternalEnergy /= 2;
|
||||
|
||||
var mix = _atmos.GetContainingMixture((uid, Transform(uid)), true, true) ?? new();
|
||||
mix.Temperature += sm.AVHeatAccumulator * 4;
|
||||
sm.AVHeatAccumulator /= sm.ThermalСonductivity;
|
||||
}
|
||||
/// <summary>
|
||||
/// React to damage dealt by all doodads.
|
||||
/// </summary>
|
||||
private void ProcessDamage(EntityUid uid, SupermatterComponent sm)
|
||||
{
|
||||
var additiveTempBase = Atmospherics.T0C + SupermatterComponent.HeatPenaltyThreshold;
|
||||
var tempLimitBase = additiveTempBase;
|
||||
var tempLimitGas = sm.GasHeatResistance * additiveTempBase;
|
||||
var tempLimitMoles = Math.Clamp(2 - sm.AbsorbedGasMix.TotalMoles / 100, 0, 1) * additiveTempBase;
|
||||
|
||||
sm.TempLimit = Math.Max(tempLimitBase + tempLimitGas + tempLimitMoles, Atmospherics.TCMB);
|
||||
|
||||
var damageHeat = Math.Clamp((sm.AbsorbedGasMix.Temperature - sm.TempLimit) / 24000, 0, .15f);
|
||||
var damagePower = Math.Clamp((sm.InternalEnergy - SupermatterComponent.PowerPenaltyThreshold), 0, .1f);
|
||||
var damageMoles = Math.Clamp((sm.AbsorbedGasMix.TotalMoles - SupermatterComponent.MolePenaltyThreshold) / 3200, 0, .1f);
|
||||
|
||||
var damageHealHeat = 0f;
|
||||
|
||||
if (sm.AbsorbedGasMix.TotalMoles > 0)
|
||||
damageHealHeat = Math.Clamp((sm.AbsorbedGasMix.TotalMoles - sm.TempLimit) / 6000, -.1f, 0);
|
||||
|
||||
var totalDamage = damageHeat + damagePower + damageMoles + damageHealHeat;
|
||||
var oldDamage = sm.Damage;
|
||||
sm.Damage += Math.Max(totalDamage, 0);
|
||||
|
||||
if (sm.Damage >= sm.DelaminationPoint && !sm.AreWeDelaming)
|
||||
{
|
||||
sm.AreWeDelaming = true;
|
||||
SupermatterAlert(uid, Loc.GetString("supermatter-announcement-delam"));
|
||||
}
|
||||
|
||||
if (sm.Damage > sm.DamageDangerPoint && _random.Prob(.0001f))
|
||||
GenerateAnomaly(uid);
|
||||
}
|
||||
/// <summary>
|
||||
/// Process waste, release hot plasma and oxygen.
|
||||
/// </summary>
|
||||
private void ProcessWaste(EntityUid uid, SupermatterComponent sm)
|
||||
{
|
||||
sm.WasteMultiplier = Math.Clamp(1f + sm.GasHeatModifier, .5f, float.PositiveInfinity);
|
||||
var mix = _atmos.GetContainingMixture((uid, Transform(uid)), true, true) ?? new();
|
||||
var mergeMix = sm.AbsorbedGasMix;
|
||||
|
||||
mergeMix.Temperature += .65f * sm.WasteMultiplier * SupermatterComponent.ThermalReleaseModifier;
|
||||
mergeMix.Temperature = Math.Clamp(mergeMix.Temperature, Atmospherics.TCMB, 2500 * sm.WasteMultiplier);
|
||||
|
||||
mergeMix.AdjustMoles(Gas.Plasma, Math.Max(.65f * sm.InternalEnergy * sm.WasteMultiplier * SupermatterComponent.PlasmaReleaseModifier, 0));
|
||||
mergeMix.AdjustMoles(Gas.Oxygen, Math.Max(.65f * sm.InternalEnergy * sm.WasteMultiplier * SupermatterComponent.OxygenReleaseModifier, 0));
|
||||
|
||||
_atmos.Merge(mix, mergeMix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swaps out ambience sounds whether the SM is delamming or not.
|
||||
/// </summary>
|
||||
private void HandleSound(EntityUid uid, SupermatterComponent sm)
|
||||
{
|
||||
var ambienceComp = Comp<AmbientSoundComponent>(uid);
|
||||
|
||||
if (sm.AreWeDelaming)
|
||||
{
|
||||
if (sm.CurrentAmbience != sm.DelamAmbienceSound)
|
||||
sm.CurrentAmbience = sm.DelamAmbienceSound;
|
||||
}
|
||||
else if (sm.CurrentAmbience != sm.CalmAmbienceSound)
|
||||
sm.CurrentAmbience = sm.CalmAmbienceSound;
|
||||
|
||||
if (ambienceComp.Sound != sm.CurrentAmbience)
|
||||
_ambience.SetSound(uid, sm.CurrentAmbience, ambienceComp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make console alerts, set station codes, etc. etc.
|
||||
/// </summary>
|
||||
/// <param name="customSender"> If true, the message will be sent from Central Command </param>
|
||||
public void SupermatterAlert(EntityUid uid, string message, bool customSender = false)
|
||||
{
|
||||
_chat.DispatchStationAnnouncement(uid, message, customSender ? "Central Command" : Loc.GetString("supermatter-announcement-sender"), playDefault: false, playTts: true, colorOverride: Color.Yellow);
|
||||
}
|
||||
|
||||
private void GenerateAnomaly(EntityUid uid, float amount = 1)
|
||||
{
|
||||
var stationUid = _station.GetOwningStation(uid);
|
||||
|
||||
if (stationUid == null || !TryComp<StationDataComponent>(stationUid, out var data))
|
||||
return;
|
||||
|
||||
var grid = _station.GetLargestGrid(data);
|
||||
|
||||
if (grid == null)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < amount; i++)
|
||||
{
|
||||
_anomaly.SpawnOnRandomGridLocation((EntityUid)grid, "RandomAnomalySpawner");
|
||||
_adminLogger.Add(LogType.Anomaly, LogImpact.Medium, $"An anomaly has been spawned by the supermatter crystal.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vaporizes the targeted uid.
|
||||
/// </summary>
|
||||
private void Vaporize(EntityUid uid, EntityUid smUid)
|
||||
{
|
||||
if (EntityManager.IsQueuedForDeletion(uid))
|
||||
return;
|
||||
|
||||
if (_tagSystem.HasTag(uid, "EmitterBolt")
|
||||
|| HasComp<SingularityComponent>(uid))
|
||||
return;
|
||||
|
||||
if (TryComp<SupermatterComponent>(smUid, out var sm))
|
||||
sm.AVExternalDamage += 1f;
|
||||
|
||||
_sound.PlayPvs(VaporizeSound, smUid);
|
||||
EntityManager.QueueDeleteEntity(uid);
|
||||
|
||||
// getting discombobulated by the SM is the same as permanent round removal so why not log that
|
||||
_adminLogger.Add(LogType.Action, LogImpact.High, $"{EntityManager.ToPrettyString(uid):player} has been vaporized by the supermatter.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle supermatter delamination and the end of the station.
|
||||
/// </summary>
|
||||
private void Delaminate(EntityUid uid, SupermatterComponent sm)
|
||||
{
|
||||
sm.PreferredDelamType = sm.PreferredDelamType ?? (int)ChooseDelam(sm);
|
||||
Delaminate(uid, sm, (DelamType)sm.PreferredDelamType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle supermatter delamination based on it's type.
|
||||
/// </summary>
|
||||
private void Delaminate(EntityUid uid, SupermatterComponent sm, DelamType type)
|
||||
{
|
||||
GenerateAnomaly(uid, _random.Next(2, 4));
|
||||
|
||||
var prototypeId = string.Empty;
|
||||
switch (type)
|
||||
{
|
||||
case DelamType.Explosion:
|
||||
default:
|
||||
_explosion.TriggerExplosive(uid); return;
|
||||
case DelamType.Tesla:
|
||||
prototypeId = sm.TeslaPrototype; break;
|
||||
case DelamType.Singularity:
|
||||
prototypeId = sm.SingularityPrototype; break;
|
||||
case DelamType.ResonanceCascade:
|
||||
prototypeId = sm.SupermatterKudzuPrototype; break;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(prototypeId))
|
||||
return;
|
||||
EntityManager.SpawnEntity(prototypeId, Transform(uid).Coordinates);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Choose a prefered delamination type. The supermatter is picky.
|
||||
/// </summary>
|
||||
private DelamType ChooseDelam(SupermatterComponent sm)
|
||||
{
|
||||
if (sm.AbsorbedGasMix.TotalMoles >= SupermatterComponent.MolePenaltyThreshold)
|
||||
return DelamType.Singularity;
|
||||
|
||||
if (sm.InternalEnergy > SupermatterComponent.PowerPenaltyThreshold)
|
||||
return DelamType.Tesla;
|
||||
|
||||
// todo: add resonance cascade when hypernob and antinob gases get added
|
||||
// or a destabilizing crystal. bet it will take years :godo:
|
||||
|
||||
return DelamType.Explosion;
|
||||
}
|
||||
/// <summary>
|
||||
/// Handle the delamination countdown, alerts, etc.
|
||||
/// </summary>
|
||||
private void DelamCountdown(EntityUid uid, SupermatterComponent sm)
|
||||
{
|
||||
if (!sm.DelamAnnouncementHappened)
|
||||
{
|
||||
var delamType = ChooseDelam(sm);
|
||||
var stationUid = _station.GetStationInMap(Transform(uid).MapID);
|
||||
|
||||
var alertLevel = string.Empty;
|
||||
var announcementLoc = string.Empty;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(Loc.GetString("supermatter-announcement-delam"));
|
||||
switch (delamType)
|
||||
{
|
||||
case DelamType.Explosion:
|
||||
default:
|
||||
announcementLoc = "supermatter-announcement-delam-explosion";
|
||||
alertLevel = "yellow";
|
||||
break;
|
||||
case DelamType.Tesla:
|
||||
announcementLoc = "supermatter-announcement-delam-tesla";
|
||||
alertLevel = "delta";
|
||||
break;
|
||||
case DelamType.Singularity:
|
||||
announcementLoc = "supermatter-announcement-delam-singuloose";
|
||||
alertLevel = "delta";
|
||||
break;
|
||||
case DelamType.ResonanceCascade:
|
||||
announcementLoc = "supermatter-announcement-delam-cascade";
|
||||
alertLevel = "delta";
|
||||
break;
|
||||
}
|
||||
sb.AppendLine(" " + Loc.GetString(announcementLoc));
|
||||
sb.Append(Loc.GetString("supermatter-announcement-delam-countdown", ("seconds", sm.DelamCountdownTimer)));
|
||||
// make it cancellable in case there are crazy engineers that managed to contain the delam
|
||||
if (stationUid != null)
|
||||
_alert.SetLevel(stationUid.Value, alertLevel, true, true, true, false);
|
||||
|
||||
SupermatterAlert(uid, sb.ToString());
|
||||
|
||||
sm.DelamAnnouncementHappened = true;
|
||||
}
|
||||
|
||||
if (sm.Damage < sm.DelaminationPoint)
|
||||
{
|
||||
// yay!
|
||||
sm.DelamCountdownAccumulator = 0;
|
||||
sm.DelamAnnouncementHappened = false;
|
||||
sm.AreWeDelaming = false;
|
||||
SupermatterAlert(uid, Loc.GetString("supermatter-announcement-safe"));
|
||||
return;
|
||||
}
|
||||
if (sm.DelamCountdownAccumulator >= sm.DelamCountdownTimer) // uh oh
|
||||
Delaminate(uid, sm);
|
||||
sm.DelamCountdownAccumulator++;
|
||||
}
|
||||
|
||||
private void OnCollide(EntityUid uid, SupermatterComponent sm, StartCollideEvent args)
|
||||
{
|
||||
if (!sm.Activated)
|
||||
sm.Activated = true;
|
||||
|
||||
Vaporize(args.OtherEntity, uid);
|
||||
}
|
||||
|
||||
private void OnClick(EntityUid uid, SupermatterComponent sm, InteractUsingEvent args)
|
||||
{
|
||||
if (HasComp<SharpComponent>(args.Used))
|
||||
{
|
||||
if (sm.Damage >= 100)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("supermatter-tamper-fail"), args.User, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasComp<SMCuttableComponent>(args.Used))
|
||||
{
|
||||
_adminLogger.Add(LogType.Action, LogImpact.High, $"{EntityManager.ToPrettyString(args.User):player} is trying to extract a sliver from the supermatter crystal.");
|
||||
_popup.PopupEntity(Loc.GetString("supermatter-tamper-begin"), args.User, args.User);
|
||||
|
||||
var doAfterArgs = new DoAfterArgs(EntityManager, args.User, 30, new SupermatterDoAfterEvent(), uid, target: uid, used: args.Used)
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
BreakOnHandChange = true,
|
||||
BreakOnMove = true,
|
||||
BreakOnWeightlessMove = false,
|
||||
NeedHand = true,
|
||||
RequireCanInteract = true,
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfterArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vaporize(args.Used, uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGetSliver(EntityUid uid, SupermatterComponent sm, SupermatterDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
sm.Damage += 10; // your criminal actions will not go unnoticed
|
||||
SupermatterAlert(uid, Loc.GetString("supermatter-announcement-tamper", ("integrity", (int)(100 - sm.Damage))));
|
||||
|
||||
Spawn(sm.SliverPrototype, _transform.GetMapCoordinates(args.User));
|
||||
_popup.PopupEntity(Loc.GetString("supermatter-tamper-end"), args.User, args.User);
|
||||
}
|
||||
|
||||
private void OnGetHit(EntityUid uid, SupermatterComponent sm, DamageChangedEvent args)
|
||||
{
|
||||
if (!sm.Activated)
|
||||
sm.Activated = true;
|
||||
|
||||
sm.AVExternalDamage += args.DamageDelta?.GetTotal().Value / 100 ?? 0;
|
||||
}
|
||||
|
||||
private void OnExamine(EntityUid uid, SupermatterComponent sm, ExaminedEvent args)
|
||||
{
|
||||
if (args.IsInDetailsRange) // get all close to it
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("supermatter-examine-integrity", ("integrity", (int)(100 - sm.Damage))));
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Content.Server/_Starlight/Energy/Supermatter/Const.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Physics;
|
||||
|
||||
namespace Content.Server.Starlight.Energy.Supermatter;
|
||||
internal static class Const
|
||||
{
|
||||
public static FixedPoint2 HeatPercent = 0.82f;
|
||||
public static FixedPoint2 BreakPercent = 0.04f;
|
||||
public static FixedPoint2 LightingPercent = 0.03f;
|
||||
public static FixedPoint2 RadiationPercent = 0.11f;
|
||||
|
||||
public static FixedPoint2 DamageMultiplayer = 3.14f;
|
||||
|
||||
public static GasProperties[] GasProperties =
|
||||
[
|
||||
new (0.24f, 1.20f, 1.4f), // oxygen
|
||||
new (0.20f, 1.46f, 1.5f), // nitrogen
|
||||
new (0.12f, 2.21f, 3.5f), // carbon dioxide
|
||||
new (0.60f, 0.61f, 1.3f), // plasma
|
||||
new (0.30f, 0.45f, 1.2f), // tritium
|
||||
new (0.14f, 2.31f, 2.5f), // vapor
|
||||
new (0.16f, 2.11f, 4.4f), // ommonium
|
||||
new (0.13f, 2.19f, 2.2f), // nitrous oxide
|
||||
new (1.00f, 0.01f, 1.1f), // frezon
|
||||
];
|
||||
|
||||
public static float MinPressure = 33f;
|
||||
public static float MaxPressure = 303.9f;
|
||||
|
||||
public static float MaxTemperature = Atmospherics.T0C + 150;
|
||||
|
||||
public static float EvaporationCompensation = 10;
|
||||
|
||||
public static FixedPoint2 MaxDamagePerSecond = (100f / 120f) + RegenerationPerSecond; // Ensures it takes at least 2 minutes to deplete
|
||||
public static FixedPoint2 RegenerationPerSecond = 0.3f;
|
||||
|
||||
public static string[] AudioCrack = ["/Audio/_Starlight/Effects/supermatter/crystal_crack_1.ogg", "/Audio/_Starlight/Effects/supermatter/crystal_crack_2.ogg"];
|
||||
public static string[] AudioBurn = ["/Audio/_Starlight/Effects/supermatter/burning_1.ogg", "/Audio/_Starlight/Effects/supermatter/burning_2.ogg", "/Audio/_Starlight/Effects/supermatter/burning_3.ogg"];
|
||||
public static string AudioEvaporate = "/Audio/_Starlight/Effects/supermatter/emitter2.ogg";
|
||||
}
|
||||
public record struct GasProperties(float HeatTransferPerMole, float HeatModifier, float RadiationStability);
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Lightning;
|
||||
using Content.Server.Radio.EntitySystems;
|
||||
using Content.Server.Starlight.Energy.Supermatter;
|
||||
using Content.Shared.Abilities.Goliath;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Coordinates.Helpers;
|
||||
using Content.Shared.Directions;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Starlight.Energy.Supermatter;
|
||||
|
||||
public sealed class SupermatterCascadeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
|
||||
private readonly LinkedList<Branch> _branches = [];
|
||||
private LinkedListNode<Branch>? node;
|
||||
private readonly string[] _prototypes = ["Cascad1", "Cascad2", "Cascad3", "Cascad4", "Cascad5", "Cascad6"];
|
||||
public override void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
node ??= _branches.First;
|
||||
if (node == null) return;
|
||||
var branch = node.Value;
|
||||
var nextNode = node.Next;
|
||||
|
||||
branch.Lifetime--;
|
||||
if (branch.Lifetime <= 0)
|
||||
{
|
||||
_branches.Remove(node);
|
||||
node = nextNode;
|
||||
return;
|
||||
}
|
||||
|
||||
var rand = _random.Next(0, 100);
|
||||
|
||||
if (rand < 10)
|
||||
{
|
||||
branch.Direction = branch.RotateLeft();
|
||||
}
|
||||
else if (rand < 20)
|
||||
{
|
||||
branch.Direction = branch.RotateRight();
|
||||
}
|
||||
else if (rand < 25 && _branches.Count < 10)
|
||||
{
|
||||
var leftBranch = new Branch
|
||||
{
|
||||
Coordinates = branch.Coordinates,
|
||||
Direction = branch.RotateLeft(),
|
||||
Lifetime = branch.Lifetime
|
||||
};
|
||||
var rightBranch = new Branch
|
||||
{
|
||||
Coordinates = branch.Coordinates,
|
||||
Direction = branch.RotateRight(),
|
||||
Lifetime = branch.Lifetime
|
||||
};
|
||||
|
||||
_branches.AddLast(leftBranch);
|
||||
_branches.AddLast(rightBranch);
|
||||
|
||||
_branches.Remove(node);
|
||||
node = nextNode;
|
||||
return;
|
||||
}
|
||||
|
||||
branch.Coordinates = branch.Coordinates.Offset(branch.Direction);
|
||||
if (_transform.GetGrid(branch.Coordinates) is not { } grid
|
||||
|| !TryComp<MapGridComponent>(grid, out var gridComp)
|
||||
|| !_map.TryGetTileRef(grid, gridComp, branch.Coordinates, out var tileRef)
|
||||
|| tileRef.IsSpace())
|
||||
{
|
||||
_branches.Remove(node);
|
||||
node = nextNode;
|
||||
return;
|
||||
}
|
||||
branch.Coordinates = branch.Coordinates.SnapToGrid(gridComp);
|
||||
|
||||
foreach (var entity in _lookup.GetEntitiesIntersecting(branch.Coordinates))
|
||||
QueueDel(entity);
|
||||
|
||||
SpawnAttachedTo(_random.Pick(_prototypes), branch.Coordinates);
|
||||
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
public void StartCascade(EntityCoordinates coordinates)
|
||||
{
|
||||
for (int i = 0; i < 8; i += 2)
|
||||
_branches.AddLast(new Branch
|
||||
{
|
||||
Coordinates = coordinates,
|
||||
Direction = (Direction)i,
|
||||
Lifetime = 100
|
||||
});
|
||||
}
|
||||
|
||||
private sealed class Branch
|
||||
{
|
||||
public EntityCoordinates Coordinates { get; set; }
|
||||
public Direction Direction { get; set; }
|
||||
public int Lifetime { get; set; }
|
||||
|
||||
public Direction RotateLeft() => Direction switch
|
||||
{
|
||||
Direction.North => Direction.NorthWest,
|
||||
Direction.NorthWest => Direction.West,
|
||||
Direction.West => Direction.SouthWest,
|
||||
Direction.SouthWest => Direction.South,
|
||||
Direction.South => Direction.SouthEast,
|
||||
Direction.SouthEast => Direction.East,
|
||||
Direction.East => Direction.NorthEast,
|
||||
Direction.NorthEast => Direction.North,
|
||||
_ => Direction,
|
||||
};
|
||||
|
||||
public Direction RotateRight() => Direction switch
|
||||
{
|
||||
Direction.North => Direction.NorthEast,
|
||||
Direction.NorthEast => Direction.East,
|
||||
Direction.East => Direction.SouthEast,
|
||||
Direction.SouthEast => Direction.South,
|
||||
Direction.South => Direction.SouthWest,
|
||||
Direction.SouthWest => Direction.West,
|
||||
Direction.West => Direction.NorthWest,
|
||||
Direction.NorthWest => Direction.North,
|
||||
_ => Direction,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Lightning;
|
||||
using Content.Server.Radio.EntitySystems;
|
||||
using Content.Server.Starlight.Energy.Supermatter;
|
||||
using Content.Shared.Abilities.Goliath;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Projectiles;
|
||||
using Content.Shared.Radiation.Components;
|
||||
using Content.Shared.Radio;
|
||||
using Content.Shared.Singularity.Components;
|
||||
using Content.Shared.Starlight.Energy.Supermatter;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Toolshed.TypeParsers;
|
||||
|
||||
namespace Content.Server.Starlight.Energy.Supermatter;
|
||||
|
||||
public sealed class SupermatterSystem : AccUpdateEntitySystem
|
||||
{
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly LightningSystem _lightning = default!;
|
||||
[Dependency] private readonly RadioSystem _radioSystem = default!;
|
||||
[Dependency] private readonly SupermatterCascadeSystem _cascade = default!;
|
||||
[Dependency] private readonly IChatManager _chat = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private readonly Dictionary<EntityUid, Entity<SupermatterComponent>> _supermatters = [];
|
||||
private DamageGroupPrototype? _brute;
|
||||
private DamageGroupPrototype? _burn;
|
||||
private RadioChannelPrototype? _engi;
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<SupermatterComponent, ComponentInit>(AddSupermatter);
|
||||
SubscribeLocalEvent<SupermatterComponent, ComponentShutdown>(RemoveSupermatter);
|
||||
|
||||
SubscribeLocalEvent<SupermatterComponent, EndCollideEvent>(OnCollide);
|
||||
SubscribeLocalEvent<SupermatterComponent, InteractHandEvent>(OnInteract);
|
||||
}
|
||||
|
||||
private void OnInteract(Entity<SupermatterComponent> ent, ref InteractHandEvent args)
|
||||
{
|
||||
if (HasComp<GhostComponent>(args.User)) return;
|
||||
|
||||
_audio.PlayPvs(Const.AudioEvaporate, ent.Owner);
|
||||
|
||||
float damage = 1;
|
||||
if (TryComp<FixturesComponent>(args.User, out var fixture))
|
||||
damage = fixture.Fixtures.Select(x => x.Value.Density).Aggregate((i, p) => p + i) / 3;
|
||||
|
||||
_burn ??= _prototypes.Index<DamageGroupPrototype>("Burn");
|
||||
_damageable.TryChangeDamage(ent.Owner, new(_burn, damage), true);
|
||||
|
||||
QueueDel(args.User);
|
||||
}
|
||||
|
||||
private void OnCollide(Entity<SupermatterComponent> ent, ref EndCollideEvent args)
|
||||
{
|
||||
ent.Comp.Activated = true;
|
||||
|
||||
if (HasComp<ProjectileComponent>(args.OtherEntity)
|
||||
|| HasComp<SingularityComponent>(args.OtherEntity)) return;
|
||||
|
||||
_audio.PlayPvs(Const.AudioEvaporate, ent.Owner);
|
||||
float damage = 1;
|
||||
if (TryComp<FixturesComponent>(args.OtherEntity, out var fixture))
|
||||
damage = fixture.Fixtures.Select(x => x.Value.Density).Aggregate((i, p) => p + i) / 3;
|
||||
|
||||
_burn ??= _prototypes.Index<DamageGroupPrototype>("Burn");
|
||||
_damageable.TryChangeDamage(ent.Owner, new(_burn, damage), true);
|
||||
|
||||
QueueDel(args.OtherEntity);
|
||||
}
|
||||
private void AddSupermatter(Entity<SupermatterComponent> ent, ref ComponentInit args) => _supermatters.TryAdd(ent.Owner, ent);
|
||||
private void RemoveSupermatter(Entity<SupermatterComponent> ent, ref ComponentShutdown args) => _supermatters.Remove(ent.Owner);
|
||||
|
||||
protected override float Threshold { get; set; } = 1f;
|
||||
protected override void AccUpdate()
|
||||
{
|
||||
foreach (var supermatter in _supermatters)
|
||||
Handle(supermatter.Value);
|
||||
}
|
||||
|
||||
private void Handle(Entity<SupermatterComponent> supermatter)
|
||||
{
|
||||
if (!supermatter.Comp.Activated) return;
|
||||
|
||||
HandleDamage(supermatter);
|
||||
HandleGas(supermatter);
|
||||
HandleRadiation(supermatter);
|
||||
HandleLighting(supermatter);
|
||||
HandleDestruction(supermatter);
|
||||
NotifyCascad(supermatter);
|
||||
Cascad(supermatter);
|
||||
}
|
||||
|
||||
private void Cascad(Entity<SupermatterComponent> supermatter)
|
||||
{
|
||||
if (supermatter.Comp.Durability > 0.01) return;
|
||||
|
||||
_cascade.StartCascade(Transform(supermatter.Owner).Coordinates);
|
||||
QueueDel(supermatter.Owner);
|
||||
}
|
||||
|
||||
private void NotifyCascad(Entity<SupermatterComponent> supermatter)
|
||||
{
|
||||
var currentDurability = (int)Math.Floor(supermatter.Comp.Durability.Float());
|
||||
var lastDurability = (int)Math.Floor(supermatter.Comp.LastSendedDurability.Float());
|
||||
_engi ??= _prototypes.Index<RadioChannelPrototype>("Engineering");
|
||||
|
||||
if (Math.Abs(currentDurability - lastDurability) < 5)
|
||||
return;
|
||||
|
||||
supermatter.Comp.LastSendedDurability = supermatter.Comp.Durability;
|
||||
|
||||
if (currentDurability > lastDurability)
|
||||
_radioSystem.SendRadioMessage(supermatter.Owner, $"The crystal is regenerating. Durability: {currentDurability}%", _engi, supermatter.Owner);
|
||||
else switch (currentDurability)
|
||||
{
|
||||
case > 75: _radioSystem.SendRadioMessage(supermatter.Owner, $"Attention! The crystal is destabilizing. Durability: {currentDurability}%", _engi, supermatter.Owner); break;
|
||||
case > 50: _chat.DispatchServerAnnouncement($"Attention! The crystal is destabilizing. Durability: {currentDurability}%", Color.Yellow); break;
|
||||
case > 25: _chat.DispatchServerAnnouncement($"Critical state of the crystal! Durability: {currentDurability}%", Color.OrangeRed); break;
|
||||
default: _chat.DispatchServerAnnouncement($"Crystal destruction is inevitable. Current durability: {currentDurability}%", Color.Red); break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDestruction(Entity<SupermatterComponent> supermatter)
|
||||
{
|
||||
var damageToApply = MathHelper.Clamp((supermatter.Comp.AccBreak / 10) - Const.RegenerationPerSecond, -Const.RegenerationPerSecond, Const.MaxDamagePerSecond);
|
||||
supermatter.Comp.AccBreak = 0;
|
||||
|
||||
supermatter.Comp.Durability = MathHelper.Clamp(supermatter.Comp.Durability - damageToApply, 0f, 100f);
|
||||
}
|
||||
|
||||
private void HandleLighting(Entity<SupermatterComponent> supermatter)
|
||||
{
|
||||
if (supermatter.Comp.AccLighting != 0
|
||||
&& _lightning.ShootRandomLightnings(supermatter.Owner, supermatter.Comp.AccLighting.Float(), 1))
|
||||
supermatter.Comp.AccLighting = 0;
|
||||
}
|
||||
|
||||
private void HandleRadiation(Entity<SupermatterComponent> supermatter)
|
||||
{
|
||||
var radComp = EnsureComp<RadiationSourceComponent>(supermatter.Owner);
|
||||
radComp.Intensity = supermatter.Comp.AccRadiation.Float();
|
||||
|
||||
supermatter.Comp.AccRadiation /= supermatter.Comp.RadiationStability;
|
||||
}
|
||||
|
||||
private void HandleGas(Entity<SupermatterComponent> supermatter)
|
||||
{
|
||||
var gas = _atmosphere.GetTileMixture(supermatter.Owner, true) ?? new();
|
||||
DamageByPressure(supermatter, gas);
|
||||
DamageByTemperature(supermatter, gas);
|
||||
|
||||
if (gas.TotalMoles < 1) return;
|
||||
|
||||
float heatTransfer = 0;
|
||||
float heatModifier = 0;
|
||||
float radiationStability = 0;
|
||||
|
||||
for (var i = 0; i < Const.GasProperties.Length; i++)
|
||||
{
|
||||
var prop = Const.GasProperties[i];
|
||||
var percent = Math.Clamp(gas.Moles[i] / gas.TotalMoles, 0, 1);
|
||||
heatTransfer += prop.HeatTransferPerMole * gas.Moles[i];
|
||||
heatModifier += prop.HeatModifier * percent;
|
||||
radiationStability += prop.RadiationStability * percent;
|
||||
}
|
||||
|
||||
supermatter.Comp.RadiationStability = MathHelper.Clamp(radiationStability, 1, 10);
|
||||
|
||||
ProcessHeat(supermatter, gas, heatTransfer, heatModifier);
|
||||
TryCompensateDamage(supermatter, gas);
|
||||
}
|
||||
|
||||
private static void TryCompensateDamage(Entity<SupermatterComponent> supermatter, GasMixture gas)
|
||||
{
|
||||
var breakDelta = supermatter.Comp.AccBreak > Const.EvaporationCompensation ? Const.EvaporationCompensation : supermatter.Comp.AccBreak;
|
||||
if (breakDelta == 0) return;
|
||||
supermatter.Comp.AccBreak -= breakDelta;
|
||||
|
||||
gas.AdjustMoles((int)Gas.Tritium, breakDelta.Float()/2);
|
||||
|
||||
gas.AdjustMoles((int)Gas.Oxygen, breakDelta.Float()*4);
|
||||
}
|
||||
|
||||
private static void ProcessHeat(Entity<SupermatterComponent> supermatter, GasMixture gas, float heatTransfer, float heatModifier)
|
||||
{
|
||||
var accHeat = supermatter.Comp.AccHeat.Float();
|
||||
var heatDelta = heatTransfer <= accHeat ? heatTransfer : accHeat;
|
||||
|
||||
accHeat = MathHelper.Clamp(accHeat - heatDelta, 0, 9999); ;
|
||||
supermatter.Comp.AccHeat = 0;
|
||||
gas.Temperature += heatDelta * heatModifier;
|
||||
supermatter.Comp.AccBreak += accHeat;
|
||||
}
|
||||
|
||||
private void DamageByTemperature(Entity<SupermatterComponent> supermatter, GasMixture gas)
|
||||
{
|
||||
if (gas.Temperature <= Const.MaxTemperature) return;
|
||||
_audio.PlayPvs(_random.Pick(Const.AudioBurn), supermatter.Owner);
|
||||
_burn ??= _prototypes.Index<DamageGroupPrototype>("Burn");
|
||||
DamageSpecifier damage = new(_burn, Const.MaxTemperature - gas.Temperature);
|
||||
_damageable.TryChangeDamage(supermatter.Owner, damage, true);
|
||||
}
|
||||
|
||||
private void DamageByPressure(Entity<SupermatterComponent> supermatter, GasMixture gas)
|
||||
{
|
||||
if (gas.Pressure >= Const.MinPressure && gas.Pressure <= Const.MaxPressure) return;
|
||||
_audio.PlayPvs(_random.Pick(Const.AudioCrack), supermatter.Owner);
|
||||
_brute ??= _prototypes.Index<DamageGroupPrototype>("Brute");
|
||||
DamageSpecifier damage = new(_brute, Math.Max(Const.MinPressure - gas.Pressure, gas.Pressure - Const.MaxPressure) / 100);
|
||||
_damageable.TryChangeDamage(supermatter.Owner, damage, true);
|
||||
}
|
||||
|
||||
private void HandleDamage(Entity<SupermatterComponent> supermatter)
|
||||
{
|
||||
EnsureComp<DamageableComponent>(supermatter.Owner, out var damageable);
|
||||
var trueDamage = damageable.TotalDamage * Const.DamageMultiplayer;
|
||||
_damageable.TryChangeDamage(supermatter.Owner, damageable.Damage.Invert(), true);
|
||||
|
||||
supermatter.Comp.AccBreak = MathHelper.Clamp(supermatter.Comp.AccBreak + (trueDamage * Const.BreakPercent), 0, 9999);
|
||||
supermatter.Comp.AccHeat = MathHelper.Clamp(supermatter.Comp.AccHeat + (trueDamage * Const.HeatPercent), 0, 9999);
|
||||
supermatter.Comp.AccLighting = MathHelper.Clamp(supermatter.Comp.AccLighting + (trueDamage * Const.LightingPercent), 0, 25);
|
||||
supermatter.Comp.AccRadiation = MathHelper.Clamp(supermatter.Comp.AccRadiation + (trueDamage * Const.RadiationPercent), 0, 100);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ namespace Content.Shared.Atmos
|
|||
public static GasMixture SpaceGas => new() {Volume = Atmospherics.CellVolume, Temperature = Atmospherics.TCMB, Immutable = true};
|
||||
|
||||
// No access, to ensure immutable mixtures are never accidentally mutated.
|
||||
[Access(typeof(SharedAtmosphereSystem), typeof(SharedAtmosDebugOverlaySystem), typeof(GasEnumerator), Other = AccessPermissions.None)]
|
||||
[Access(typeof(SharedAtmosphereSystem), typeof(SharedAtmosDebugOverlaySystem), typeof(GasEnumerator), Other = AccessPermissions.Read)] // Sunrise-Edit
|
||||
[DataField]
|
||||
public float[] Moles = new float[Atmospherics.AdjustedNumberOfGases];
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,12 @@ public sealed partial class FlatpackComponent : Component
|
|||
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||
public ProtoId<ToolQualityPrototype> QualityNeeded = "Pulsing";
|
||||
|
||||
/// <summary>
|
||||
/// Is Flatpack allowed to unpuck on tables? (For microwaves, etc.)
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool AllowUnpackOnTables = false; // Starlight-edit
|
||||
|
||||
/// <summary>
|
||||
/// The entity that is spawned when this object is unpacked.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Content.Shared._Sunrise.Economy;
|
||||
using System.Linq;
|
||||
using Content.Shared.Construction.Components;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
|
|
@ -6,6 +7,7 @@ using Content.Shared.Database;
|
|||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Materials;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Tools.Systems;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
|
|
@ -31,6 +33,7 @@ public abstract class SharedFlatpackSystem : EntitySystem
|
|||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedToolSystem _tool = default!;
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
|
|
@ -80,10 +83,12 @@ public abstract class SharedFlatpackSystem : EntitySystem
|
|||
var buildPos = _map.TileIndicesFor(grid, gridComp, xform.Coordinates);
|
||||
var coords = _map.ToCenterCoordinates(grid, buildPos);
|
||||
|
||||
// TODO FLATPAK
|
||||
// Make this logic smarter. This should eventually allow for shit like building microwaves on tables and such.
|
||||
// Also: make it ignore ghosts
|
||||
if (_entityLookup.AnyEntitiesIntersecting(coords, LookupFlags.Dynamic | LookupFlags.Static))
|
||||
// TODO FLATPACK
|
||||
// make it ignore ghosts
|
||||
// Starlight-start
|
||||
if (_entityLookup.GetEntitiesIntersecting(coords, LookupFlags.Dynamic | LookupFlags.Static)
|
||||
.Any(entity => entity != uid && (!_tag.HasTag(entity, "Table") || !ent.Comp.AllowUnpackOnTables)))
|
||||
// Starlight-end
|
||||
{
|
||||
// this popup is on the server because the predicts on the intersection is crazy
|
||||
if (_net.IsServer)
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Supermatter;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class SupermatterDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
|
||||
}
|
||||
19
Content.Shared/_Starlight/Abstract/AccUpdateEntitySystem.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
namespace Content.Shared.Abilities.Goliath;
|
||||
|
||||
public abstract class AccUpdateEntitySystem : EntitySystem
|
||||
{
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_accumulator += frameTime;
|
||||
if (_accumulator > Threshold)
|
||||
{
|
||||
AccUpdate();
|
||||
_accumulator = 0;
|
||||
}
|
||||
}
|
||||
protected virtual void AccUpdate()
|
||||
{
|
||||
}
|
||||
protected virtual float Threshold { get; set; } = 0.35f;
|
||||
private float _accumulator = 0f;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Starlight.Energy.Supermatter;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class SupermatterComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Activated = false;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public FixedPoint2 AccHeat = 0f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public FixedPoint2 AccRadiation = 0f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public FixedPoint2 AccLighting = 0f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public FixedPoint2 AccBreak = 0f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public FixedPoint2 RadiationStability = 1f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public FixedPoint2 Durability = 100f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public FixedPoint2 LastSendedDurability = 100f;
|
||||
}
|
||||
|
|
@ -62,8 +62,3 @@
|
|||
license: "CC-BY-4.0"
|
||||
copyright: "Taken and edited from source"
|
||||
source: "https://freesound.org/people/juskiddink/sounds/215658/"
|
||||
|
||||
- files: ["supermatter_calm.ogg", "supermatter_delam.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken from source"
|
||||
source: "https://github.com/tgstation/tgstation/blob/master/sound/machines/sm/loops"
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
- files: ["crystal_crack_1.ogg","crystal_crack_2.ogg", "burning_1.ogg", "burning_2.ogg", "burning_3.ogg"]
|
||||
license: "CC-BY-4.0"
|
||||
copyright: 'Darkrell'
|
||||
source: "https://github.com/ss14Starlight/space-station-14"
|
||||
|
||||
- files: ["emitter2.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken from tgstation"
|
||||
source: "https://github.com/tgstation/tgstation/blob/master/sound/weapons/emitter2.ogg"
|
||||
BIN
Resources/Audio/_Starlight/Effects/supermatter/burning_1.ogg
Normal file
BIN
Resources/Audio/_Starlight/Effects/supermatter/burning_2.ogg
Normal file
BIN
Resources/Audio/_Starlight/Effects/supermatter/burning_3.ogg
Normal file
BIN
Resources/Audio/_Starlight/Effects/supermatter/emitter2.ogg
Normal file
|
|
@ -4,7 +4,5 @@ ent-CMOAdvancedDefibrillatorStealObjective = { ent-BaseCMOStealObjective }
|
|||
.desc = { ent-BaseCMOStealObjective.desc }
|
||||
ent-PlutoniumCoreStealObjective = { ent-BaseTraitorStealObjective }
|
||||
.desc = { ent-BaseTraitorStealObjective.desc }
|
||||
ent-StealSupermatterSliverObjective = { ent-BaseTraitorStealObjective }
|
||||
.desc = { ent-BaseTraitorStealObjective.desc }
|
||||
ent-HandheldFaxStealObjective = { ent-BaseTraitorStealObjective }
|
||||
.desc = { ent-BaseTraitorStealObjective.desc }
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
ent-SupermatterSliver = supermatter sliver
|
||||
.desc = A shard from the station's supermatter engine. Highly radioactive.
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
objective-condition-steal-nuclear-bomb = nuclear bomb
|
||||
objective-condition-steal-supermatter-sliver = Отрежьте кусочек от кристалла суперматерии.
|
||||
objective-description-steal-supermatter-sliver = Используйте любой подходящий режущий инструмент. Лучше всего подойдёт скальпель. И постарайтесь не умереть от радиационного отравления.
|
||||
objective-description-steal-handheld-fax = You need to steal a portable fax machine from a corporate representative.
|
||||
objective-condition-steal-handheld-fax = Portable fax
|
||||
|
|
|
|||
|
|
@ -4,7 +4,5 @@ ent-CMOAdvancedDefibrillatorStealObjective = { ent-BaseCMOStealObjective }
|
|||
.desc = { ent-BaseCMOStealObjective.desc }
|
||||
ent-PlutoniumCoreStealObjective = { ent-BaseTraitorStealObjective }
|
||||
.desc = { ent-BaseTraitorStealObjective.desc }
|
||||
ent-StealSupermatterSliverObjective = { ent-BaseTraitorStealObjective }
|
||||
.desc = { ent-BaseTraitorStealObjective.desc }
|
||||
ent-HandheldFaxStealObjective = { ent-BaseTraitorStealObjective }
|
||||
.desc = { ent-BaseTraitorStealObjective.desc }
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
ent-SupermatterSliver = осколок суперматерии
|
||||
.desc = Осколок от кристалла суперматерии станции. Сильно радиоактивен.
|
||||
|
|
@ -1,3 +1,2 @@
|
|||
objective-condition-steal-nuclear-bomb = ядерную бомбу
|
||||
objective-condition-steal-supermatter-sliver = Отрежьте кусочек от кристалла суперматерии.
|
||||
objective-description-steal-supermatter-sliver = Используйте любой подходящий режущий инструмент. Лучше всего подойдёт скальпель. И постарайтесь не умереть от радиационного отравления.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# Traitor single items
|
||||
steal-target-groups-supermatter-sliver = осколок суперматерии
|
||||
steal-target-groups-hypospray = гипоспрей
|
||||
steal-target-groups-handheld-crew-monitor = портативный монитор экипажа
|
||||
steal-target-groups-clothing-outer-hardsuit-rd = экспериментальный исследовательский скафандр
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@
|
|||
layers:
|
||||
- state: fax-machine
|
||||
- type: Flatpack
|
||||
allowUnpackOnTables: true
|
||||
entity: FaxMachineBase
|
||||
|
||||
- type: entity
|
||||
|
|
@ -251,6 +252,32 @@
|
|||
- type: Flatpack
|
||||
entity: ComputerCrewMonitoring
|
||||
|
||||
- type: entity
|
||||
parent: BaseFlatpack
|
||||
id: MicrowaveFlatpack
|
||||
name: microwave flatpack
|
||||
description: A flatpack used for constructing a microwave.
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: microwave
|
||||
- type: Flatpack
|
||||
allowUnpackOnTables: true
|
||||
entity: KitchenMicrowave
|
||||
|
||||
- type: entity
|
||||
parent: BaseFlatpack
|
||||
id: SyndicateMicrowaveFlatpack
|
||||
name: microwave flatpack
|
||||
description: A flatpack used for constructing a microwave.
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: microwave
|
||||
- type: Flatpack
|
||||
allowUnpackOnTables: true
|
||||
entity: SyndicateMicrowave
|
||||
|
||||
- type: entity
|
||||
parent: BaseFlatpack
|
||||
id: HydroponicsTrayFlatpack
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
- type: entity
|
||||
parent: BaseItem
|
||||
id: SupermatterSliver
|
||||
name: supermatter sliver
|
||||
description: A shard from the station's supermatter engine. Highly radioactive.
|
||||
components:
|
||||
- type: PointLight
|
||||
enabled: true
|
||||
radius: 3
|
||||
energy: 2
|
||||
color: "#fff633"
|
||||
- type: RadiationSource
|
||||
intensity: 2.5
|
||||
- type: Icon
|
||||
sprite: Objects/Misc/supermatter_sliver.rsi
|
||||
state: icon
|
||||
- type: Sprite
|
||||
sprite: Objects/Misc/supermatter_sliver.rsi
|
||||
state: icon
|
||||
- type: StealTarget
|
||||
stealGroup: SupermatterSliver
|
||||
- type: Tag
|
||||
tags:
|
||||
- HighRiskItem
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
- type: Tag
|
||||
tags:
|
||||
- ForceFixRotations
|
||||
- Table
|
||||
|
||||
- type: entity
|
||||
id: CounterBase
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
- type: entity
|
||||
id: SupermatterCrystal
|
||||
name: supermatter crystal
|
||||
description: A strangely translucent and iridescent crystal.
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
components:
|
||||
- type: Supermatter
|
||||
- type: Transform
|
||||
anchored: true
|
||||
noRot: true
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: Glass
|
||||
- type: RadiationSource
|
||||
intensity: 0 # will be set somewhere else
|
||||
- type: Physics
|
||||
bodyType: Static
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.45,-0.45,0.45,0.45"
|
||||
density: 250
|
||||
mask:
|
||||
- FullTileMask
|
||||
layer:
|
||||
- WallLayer
|
||||
- type: CollisionWake
|
||||
enabled: false
|
||||
- type: Clickable
|
||||
- type: InteractionOutline
|
||||
- type: Sprite
|
||||
drawdepth: 2
|
||||
sprite: Structures/Power/Generation/supermatter.rsi
|
||||
state: supermatter
|
||||
- type: Icon
|
||||
sprite: Structures/Power/Generation/supermatter.rsi
|
||||
state: supermatter
|
||||
- type: PointLight
|
||||
enabled: true
|
||||
radius: 10
|
||||
energy: 5
|
||||
color: "#fff633"
|
||||
- type: AmbientSound
|
||||
range: 4
|
||||
volume: -2
|
||||
sound:
|
||||
path: /Audio/Ambience/Objects/supermatter_calm.ogg
|
||||
- type: SinguloFood
|
||||
energy: 7500
|
||||
- type: WarpPoint
|
||||
follow: true
|
||||
location: supermatter
|
||||
- type: Explosive
|
||||
explosionType: HardBomb
|
||||
totalIntensity: 10000.0
|
||||
intensitySlope: 4
|
||||
maxIntensity: 1000
|
||||
|
|
@ -26,7 +26,6 @@
|
|||
PlutoniumCoreStealObjective: 0.5
|
||||
#MultiphaseEnergygunStealObjective: 1 # Sunrise-Edit: ОСЩ больше не появляется на станции
|
||||
CMOAdvancedDefibrillatorStealObjective: 1
|
||||
StealSupermatterSliverObjective: 1
|
||||
HandheldFaxStealObjective: 1
|
||||
# Sunrise-End
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
# Traitor single items
|
||||
|
||||
- type: stealTargetGroup
|
||||
id: SupermatterSliver
|
||||
name: steal-target-groups-supermatter-sliver
|
||||
sprite:
|
||||
sprite: Objects/Misc/supermatter_sliver.rsi
|
||||
state: icon
|
||||
|
||||
- type: stealTargetGroup
|
||||
id: Hypospray
|
||||
name: steal-target-groups-hypospray
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
- type: cargoProduct
|
||||
id: SupermatterFlatpackPurchase
|
||||
icon:
|
||||
sprite: _Starlight/Objects/Specific/supermatter.rsi
|
||||
state: supermatter
|
||||
product: SupermatterFlatpack
|
||||
cost: 8000
|
||||
category: cargoproduct-category-name-engineering
|
||||
group: market
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
- type: entity
|
||||
parent: BaseStructureDynamic
|
||||
id: BaseStructureFlatpack
|
||||
name: base structure flatpack
|
||||
description: A flatpack used for constructing something.
|
||||
categories:
|
||||
- HideSpawnMenu
|
||||
components:
|
||||
- type: Animateable
|
||||
- type: Transform
|
||||
noRot: true
|
||||
- type: Icon
|
||||
sprite: Structures/Storage/Crates/generic.rsi
|
||||
state: base
|
||||
- type: Sprite
|
||||
sprite: Objects/Devices/flatpack.rsi
|
||||
layers:
|
||||
- state: base
|
||||
- state: overlay
|
||||
color: "#cec8ac"
|
||||
map: ["enum.FlatpackVisualLayers.Overlay"]
|
||||
- state: icon-default
|
||||
- type: InteractionOutline
|
||||
- type: Physics
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.4,-0.4,0.4,0.29"
|
||||
density: 50
|
||||
mask:
|
||||
- CrateMask #this is so they can go under plastic flaps
|
||||
layer:
|
||||
- MachineLayer
|
||||
- type: Appearance
|
||||
- type: Flatpack
|
||||
boardColors:
|
||||
command: "#334E6D"
|
||||
medical: "#52B4E9"
|
||||
service: "#9FED58"
|
||||
engineering: "#EFB341"
|
||||
security: "#DE3A3A"
|
||||
science: "#D381C9"
|
||||
supply: "#A46106"
|
||||
cpu_command: "#334E6D"
|
||||
cpu_medical: "#52B4E9"
|
||||
cpu_service: "#9FED58"
|
||||
cpu_engineering: "#EFB341"
|
||||
cpu_security: "#DE3A3A"
|
||||
cpu_science: "#D381C9"
|
||||
cpu_supply: "#A46106"
|
||||
- type: StaticPrice
|
||||
price: 250
|
||||
|
||||
- type: entity
|
||||
parent: [BaseStructureFlatpack, BaseEngineeringContraband]
|
||||
id: SupermatterFlatpack
|
||||
name: supermatter flatpack
|
||||
description: A flatpack used for constructing a Supermatter Crystal.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Devices/flatpack.rsi
|
||||
layers:
|
||||
- state: large
|
||||
- type: Flatpack
|
||||
entity: SupermatterCrystal
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
- type: entity
|
||||
id: SupermatterCrystal
|
||||
name: supermatter
|
||||
description: A glowing supermatter crystal, with half an ID card lying next to it, and it says "Clown pira..." on it.
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
components:
|
||||
- type: Supermatter
|
||||
- type: Transform
|
||||
noRot: true
|
||||
anchored: true
|
||||
- type: InteractionOutline
|
||||
- type: Clickable
|
||||
- type: Anchorable
|
||||
delay: 2
|
||||
- type: Physics
|
||||
bodyType: Static
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.40,-0.40,0.40,0.40"
|
||||
density: 190
|
||||
friction: 0.8
|
||||
mask:
|
||||
- FullTileMask
|
||||
layer:
|
||||
- FullTileLayer
|
||||
- type: Pullable
|
||||
- type: Sprite
|
||||
sprite: _Starlight/Objects/Specific/supermatter.rsi
|
||||
state: supermatter
|
||||
shader: unshaded
|
||||
- type: Icon
|
||||
sprite: _Starlight/Objects/Specific/supermatter.rsi
|
||||
state: supermatter
|
||||
- type: PointLight
|
||||
enabled: true
|
||||
color: "#FFFB97"
|
||||
- type: Damageable
|
||||
damageModifierSet: RGlass
|
||||
damageContainer: StructuralInorganic
|
||||
# - type: LightningTarget Tesla needs to interact too.
|
||||
# priority: 1
|
||||
|
||||
|
||||
- type: entity
|
||||
id: Cascad1
|
||||
name: cascad
|
||||
description: Consequences of the supermatter crystal's cascade failure.
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
components:
|
||||
- type: Damageable
|
||||
damageContainer: StructuralInorganic
|
||||
damageModifierSet: Glass
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 80
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: GlassBreak
|
||||
- type: Sprite
|
||||
drawdepth: Walls
|
||||
sprite: _Starlight/Objects/Specific/supermatter_cascade.rsi
|
||||
layers:
|
||||
- state: cascade_1
|
||||
- type: Icon
|
||||
sprite: _Starlight/Objects/Specific/supermatter_cascade.rsi
|
||||
state: cascade_1
|
||||
- type: Physics
|
||||
bodyType: Static
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.5,-0.5,0.5,0.5"
|
||||
layer:
|
||||
- GlassLayer
|
||||
|
||||
- type: entity
|
||||
id: Cascad2
|
||||
parent: Cascad1
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: cascade_2
|
||||
- type: Icon
|
||||
sprite: _Starlight/Objects/Specific/supermatter_cascade.rsi
|
||||
state: cascade_2
|
||||
|
||||
- type: entity
|
||||
id: Cascad3
|
||||
parent: Cascad1
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: cascade_3
|
||||
- type: Icon
|
||||
sprite: _Starlight/Objects/Specific/supermatter_cascade.rsi
|
||||
state: cascade_3
|
||||
|
||||
- type: entity
|
||||
id: Cascad4
|
||||
parent: Cascad1
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: cascade_4
|
||||
- type: Icon
|
||||
sprite: _Starlight/Objects/Specific/supermatter_cascade.rsi
|
||||
state: cascade_4
|
||||
|
||||
- type: entity
|
||||
id: Cascad5
|
||||
parent: Cascad1
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: cascade_5
|
||||
- type: Icon
|
||||
sprite: _Starlight/Objects/Specific/supermatter_cascade.rsi
|
||||
state: cascade_5
|
||||
|
||||
- type: entity
|
||||
id: Cascad6
|
||||
parent: Cascad1
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: cascade_6
|
||||
- type: Icon
|
||||
sprite: _Starlight/Objects/Specific/supermatter_cascade.rsi
|
||||
state: cascade_6
|
||||
|
|
@ -33,18 +33,6 @@
|
|||
listings:
|
||||
- UplinkCoreExtractionToolbox
|
||||
|
||||
- type: entity
|
||||
categories: [ HideSpawnMenu ]
|
||||
parent: BaseTraitorStealObjective
|
||||
id: StealSupermatterSliverObjective
|
||||
components:
|
||||
- type: Objective
|
||||
difficulty: 2.5
|
||||
- type: StealCondition
|
||||
stealGroup: SupermatterSliver
|
||||
objectiveNoOwnerText: objective-condition-steal-supermatter-sliver
|
||||
descriptionText: objective-description-steal-supermatter-sliver
|
||||
|
||||
- type: entity
|
||||
parent: BaseTraitorStealObjective
|
||||
id: HandheldFaxStealObjective
|
||||
|
|
|
|||
|
|
@ -456,3 +456,6 @@
|
|||
|
||||
- type: Tag
|
||||
id: SnapPop
|
||||
|
||||
- type: Tag
|
||||
id: Table
|
||||
|
|
|
|||
BIN
Resources/Textures/Objects/Devices/flatpack.rsi/large.png
Normal file
|
After Width: | Height: | Size: 437 B |
|
|
@ -48,6 +48,12 @@
|
|||
},
|
||||
{
|
||||
"name": "hydroponics-tray"
|
||||
},
|
||||
{
|
||||
"name": "large"
|
||||
},
|
||||
{
|
||||
"name": "microwave"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
BIN
Resources/Textures/Objects/Devices/flatpack.rsi/microwave.png
Normal file
|
After Width: | Height: | Size: 512 B |
|
Before Width: | Height: | Size: 357 B |
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"version": 1,
|
||||
"copyright": "Taken and edited from https://github.com/tgstation/tgstation/blob/master/icons/obj/antags/syndicate_tools.dmi",
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "icon"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"version": 1,
|
||||
"copyright": "Taken and edited from https://tgstation13.org/wiki/images/a/a4/Supermatter-bg.gif",
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 48
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "supermatter",
|
||||
"delays": [
|
||||
[
|
||||
0.08,
|
||||
0.08,
|
||||
0.08
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Before Width: | Height: | Size: 28 KiB |
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from https://tgstation13.org/wiki/images/a/a4/Supermatter-bg.gif",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 48
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "supermatter",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from https://tgstation13.org/wiki/images/a/a4/Supermatter-bg.gif",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "cascade_1"
|
||||
},
|
||||
{
|
||||
"name": "cascade_2"
|
||||
},
|
||||
{
|
||||
"name": "cascade_3"
|
||||
},
|
||||
{
|
||||
"name": "cascade_4"
|
||||
},
|
||||
{
|
||||
"name": "cascade_5"
|
||||
},
|
||||
{
|
||||
"name": "cascade_6"
|
||||
}
|
||||
]
|
||||
}
|
||||