feat: Перенос суперматерии
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
using Content.Shared.White.Supermatter.Components;
|
||||||
|
using Content.Shared.White.Supermatter.Systems;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Client.White.Supermatter.Systems;
|
||||||
|
|
||||||
|
public sealed class SupermatterSystem : SharedSupermatterSystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SupermatterComponent, ComponentHandleState>(HandleSupermatterState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleSupermatterState(EntityUid uid, SupermatterComponent comp, ref ComponentHandleState args)
|
||||||
|
{
|
||||||
|
if (args.Current is not SupermatterComponentState state)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
582
Content.Server/White/Supermatter/Systems/SupermatterSystem.cs
Normal file
582
Content.Server/White/Supermatter/Systems/SupermatterSystem.cs
Normal file
@@ -0,0 +1,582 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Content.Server.Alert.Click;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Physics;
|
||||||
|
using Robust.Shared.Physics.Components;
|
||||||
|
using Robust.Shared.Physics.Events;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Projectiles;
|
||||||
|
using Content.Shared.Tag;
|
||||||
|
using Content.Shared.Mobs.Components;
|
||||||
|
using Content.Shared.Radiation.Components;
|
||||||
|
using Content.Server.Audio;
|
||||||
|
using Content.Server.Atmos.EntitySystems;
|
||||||
|
using Content.Server.Chat.Systems;
|
||||||
|
using Content.Server.Explosion.EntitySystems;
|
||||||
|
using Content.Server.Explosion.Components;
|
||||||
|
using Content.Shared.Singularity.Components;
|
||||||
|
using Content.Shared.Singularity.EntitySystems;
|
||||||
|
using Content.Shared.White.Supermatter.Components;
|
||||||
|
using Content.Shared.White.Supermatter.Systems;
|
||||||
|
using Robust.Shared.Audio.Systems;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
|
namespace Content.Server.White.Supermatter.Systems
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class SupermatterSystem : SharedSupermatterSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
||||||
|
[Dependency] private readonly ChatSystem _chat = default!;
|
||||||
|
[Dependency] private readonly TagSystem _tag = default!;
|
||||||
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
|
[Dependency] private readonly ExplosionSystem _explosion = default!;
|
||||||
|
[Dependency] private readonly TransformSystem _xform = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
[Dependency] private readonly AmbientSoundSystem _ambient = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly SharedSingularitySystem _singularity = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SupermatterComponent, ComponentInit>(OnComponentInit);
|
||||||
|
SubscribeLocalEvent<SupermatterComponent, StartCollideEvent>(OnCollideEvent);
|
||||||
|
SubscribeLocalEvent<SupermatterComponent, InteractHandEvent>(OnHandInteract);
|
||||||
|
SubscribeLocalEvent<SupermatterComponent, MapInitEvent>(OnMapInit);
|
||||||
|
SubscribeLocalEvent<SupermatterComponent, ComponentGetState>(HandleSupermatterState);
|
||||||
|
SubscribeLocalEvent<SupermatterComponent, ComponentRemove>(OnComponentRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnComponentInit(EntityUid uid, SupermatterComponent component, ComponentInit args)
|
||||||
|
{
|
||||||
|
if (_random.Prob(0.2f))
|
||||||
|
{
|
||||||
|
component.DelamType = DelamType.Singulo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnComponentRemove(EntityUid uid, SupermatterComponent component, ComponentRemove args)
|
||||||
|
{
|
||||||
|
// turn off any ambient if component is removed (ex. entity deleted)
|
||||||
|
_ambient.SetAmbience(uid, false);
|
||||||
|
_audio.Stop(component.AudioEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMapInit(EntityUid uid, SupermatterComponent component, MapInitEvent args)
|
||||||
|
{
|
||||||
|
// Set the Sound
|
||||||
|
_ambient.SetAmbience(uid, true);
|
||||||
|
|
||||||
|
//Add Air to the initialized SM in the Map so it doesnt delam on default
|
||||||
|
var mixture = _atmosphere.GetContainingMixture(uid, true, true);
|
||||||
|
mixture?.AdjustMoles(Gas.Oxygen, Atmospherics.OxygenMolesStandard);
|
||||||
|
mixture?.AdjustMoles(Gas.Nitrogen, Atmospherics.NitrogenMolesStandard);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleSupermatterState(EntityUid uid, SupermatterComponent comp, ref ComponentGetState args)
|
||||||
|
{
|
||||||
|
args.State = new SupermatterComponentState(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
if (!_gameTiming.IsFirstTimePredicted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var (supermatter, xplode, rads) in EntityManager
|
||||||
|
.EntityQuery<SupermatterComponent, ExplosiveComponent, RadiationSourceComponent>())
|
||||||
|
{
|
||||||
|
var mixture = _atmosphere.GetContainingMixture(supermatter.Owner, true, true);
|
||||||
|
HandleOutput(supermatter.Owner, frameTime, supermatter, rads, mixture);
|
||||||
|
HandleDamage(supermatter.Owner, frameTime, supermatter, xplode, mixture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle outputting based off enery, damage, gas mix and radiation
|
||||||
|
/// </summary>
|
||||||
|
private void HandleOutput(
|
||||||
|
EntityUid uid,
|
||||||
|
float frameTime,
|
||||||
|
SupermatterComponent? sMcomponent = null,
|
||||||
|
RadiationSourceComponent? radcomponent = null,
|
||||||
|
Atmos.GasMixture? mixture = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref sMcomponent, ref radcomponent))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sMcomponent.AtmosUpdateAccumulator += frameTime;
|
||||||
|
|
||||||
|
if (!(sMcomponent.AtmosUpdateAccumulator > sMcomponent.AtmosUpdateTimer) || mixture is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sMcomponent.AtmosUpdateAccumulator -= sMcomponent.AtmosUpdateTimer;
|
||||||
|
|
||||||
|
//Absorbed gas from surrounding area
|
||||||
|
var absorbedGas = mixture.Remove(sMcomponent.GasEfficiency * mixture.TotalMoles);
|
||||||
|
var absorbedTotalMoles = absorbedGas.TotalMoles;
|
||||||
|
|
||||||
|
if (!(absorbedTotalMoles > 0f))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var gasStorage = sMcomponent.GasStorage;
|
||||||
|
var gasEffect = sMcomponent.GasDataFields;
|
||||||
|
|
||||||
|
//Lets get the proportions of the gasses in the mix for scaling stuff later
|
||||||
|
//They range between 0 and 1
|
||||||
|
gasStorage = gasStorage.ToDictionary(
|
||||||
|
gas => gas.Key,
|
||||||
|
gas => Math.Clamp(absorbedGas.GetMoles(gas.Key) / absorbedTotalMoles, 0, 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
//No less then zero, and no greater then one, we use this to do explosions
|
||||||
|
//and heat to power transfer
|
||||||
|
var gasmixPowerRatio = gasStorage.Sum(gas => gasStorage[gas.Key] * gasEffect[gas.Key].PowerMixRatio);
|
||||||
|
|
||||||
|
//Minimum value of -10, maximum value of 23. Effects plasma and o2 output
|
||||||
|
//and the output heat
|
||||||
|
var dynamicHeatModifier = gasStorage.Sum(gas => gasStorage[gas.Key] * gasEffect[gas.Key].HeatPenalty);
|
||||||
|
|
||||||
|
//Minimum value of -10, maximum value of 23. Effects plasma and o2 output
|
||||||
|
// and the output heat
|
||||||
|
var powerTransmissionBonus =
|
||||||
|
gasStorage.Sum(gas => gasStorage[gas.Key] * gasEffect[gas.Key].TransmitModifier);
|
||||||
|
|
||||||
|
var h2OBonus = 1 - gasStorage[Gas.WaterVapor] * 0.25f;
|
||||||
|
|
||||||
|
gasmixPowerRatio = Math.Clamp(gasmixPowerRatio, 0, 1);
|
||||||
|
dynamicHeatModifier = Math.Max(dynamicHeatModifier, 0.5f);
|
||||||
|
powerTransmissionBonus *= h2OBonus;
|
||||||
|
|
||||||
|
//Effects the damage heat does to the crystal
|
||||||
|
sMcomponent.DynamicHeatResistance = 1f;
|
||||||
|
|
||||||
|
//more moles of gases are harder to heat than fewer,
|
||||||
|
//so let's scale heat damage around them
|
||||||
|
sMcomponent.MoleHeatPenaltyThreshold =
|
||||||
|
(float) Math.Max(absorbedTotalMoles / sMcomponent.MoleHeatPenalty, 0.25);
|
||||||
|
|
||||||
|
//Ramps up or down in increments of 0.02 up to the proportion of co2
|
||||||
|
//Given infinite time, powerloss_dynamic_scaling = co2comp
|
||||||
|
//Some value between 0 and 1
|
||||||
|
if (absorbedTotalMoles > sMcomponent.PowerlossInhibitionMoleThreshold &&
|
||||||
|
gasStorage[Gas.CarbonDioxide] > sMcomponent.PowerlossInhibitionGasThreshold)
|
||||||
|
{
|
||||||
|
sMcomponent.PowerlossDynamicScaling =
|
||||||
|
Math.Clamp(
|
||||||
|
sMcomponent.PowerlossDynamicScaling + Math.Clamp(
|
||||||
|
gasStorage[Gas.CarbonDioxide] - sMcomponent.PowerlossDynamicScaling, -0.02f, 0.02f), 0f,
|
||||||
|
1f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sMcomponent.PowerlossDynamicScaling = Math.Clamp(sMcomponent.PowerlossDynamicScaling - 0.05f, 0f, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ranges from 0 to 1(1-(value between 0 and 1 * ranges from 1 to 1.5(mol / 500)))
|
||||||
|
//We take the mol count, and scale it to be our inhibitor
|
||||||
|
var powerlossInhibitor =
|
||||||
|
Math.Clamp(
|
||||||
|
1 - sMcomponent.PowerlossDynamicScaling *
|
||||||
|
Math.Clamp(absorbedTotalMoles / sMcomponent.PowerlossInhibitionMoleBoostThreshold, 1f, 1.5f),
|
||||||
|
0f, 1f);
|
||||||
|
|
||||||
|
if (sMcomponent.MatterPower != 0) //We base our removed power off one 10th of the matter_power.
|
||||||
|
{
|
||||||
|
var removedMatter = Math.Max(sMcomponent.MatterPower / sMcomponent.MatterPowerConversion, 40);
|
||||||
|
//Adds at least 40 power
|
||||||
|
sMcomponent.Power = Math.Max(sMcomponent.Power + removedMatter, 0);
|
||||||
|
//Removes at least 40 matter power
|
||||||
|
sMcomponent.MatterPower = Math.Max(sMcomponent.MatterPower - removedMatter, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//based on gas mix, makes the power more based on heat or less effected by heat
|
||||||
|
var tempFactor = gasmixPowerRatio > 0.8 ? 50f : 30f;
|
||||||
|
|
||||||
|
//if there is more pluox and n2 then anything else, we receive no power increase from heat
|
||||||
|
sMcomponent.Power =
|
||||||
|
Math.Max(
|
||||||
|
absorbedGas.Temperature * tempFactor / Atmospherics.T0C * gasmixPowerRatio + sMcomponent.Power,
|
||||||
|
0);
|
||||||
|
|
||||||
|
//Rad Pulse Calculation
|
||||||
|
radcomponent.Intensity = sMcomponent.Power * Math.Max(0, 1f + powerTransmissionBonus / 10f) * 0.003f;
|
||||||
|
|
||||||
|
//Power * 0.55 * a value between 1 and 0.8
|
||||||
|
var energy = sMcomponent.Power * sMcomponent.ReactionPowerModefier;
|
||||||
|
|
||||||
|
//Keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock
|
||||||
|
//is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall.
|
||||||
|
//Power * 0.55 * (some value between 1.5 and 23) / 5
|
||||||
|
|
||||||
|
absorbedGas.Temperature += energy * dynamicHeatModifier / sMcomponent.ThermalReleaseModifier;
|
||||||
|
absorbedGas.Temperature = Math.Max(0,
|
||||||
|
Math.Min(absorbedGas.Temperature, sMcomponent.HeatThreshold * dynamicHeatModifier));
|
||||||
|
|
||||||
|
//Calculate how much gas to release
|
||||||
|
//Varies based on power and gas content
|
||||||
|
|
||||||
|
absorbedGas.AdjustMoles(Gas.Plasma,
|
||||||
|
Math.Max(energy * dynamicHeatModifier / sMcomponent.PlasmaReleaseModifier, 0f));
|
||||||
|
|
||||||
|
absorbedGas.AdjustMoles(Gas.Oxygen,
|
||||||
|
Math.Max(
|
||||||
|
(energy + absorbedGas.Temperature * dynamicHeatModifier - Atmospherics.T0C) /
|
||||||
|
sMcomponent.OxygenReleaseModifier, 0f));
|
||||||
|
|
||||||
|
_atmosphere.Merge(mixture, absorbedGas);
|
||||||
|
|
||||||
|
var powerReduction = (float) Math.Pow(sMcomponent.Power / 500, 3);
|
||||||
|
|
||||||
|
//After this point power is lowered
|
||||||
|
//This wraps around to the begining of the function
|
||||||
|
sMcomponent.Power =
|
||||||
|
Math.Max(
|
||||||
|
sMcomponent.Power - Math.Min(powerReduction * powerlossInhibitor,
|
||||||
|
sMcomponent.Power * 0.83f * powerlossInhibitor), 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles environmental damage and dispatching damage warning
|
||||||
|
/// </summary>
|
||||||
|
private void HandleDamage(
|
||||||
|
EntityUid uid,
|
||||||
|
float frameTime,
|
||||||
|
SupermatterComponent? sMcomponent = null,
|
||||||
|
ExplosiveComponent? xplode = null,
|
||||||
|
Atmos.GasMixture? mixture = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref sMcomponent, ref xplode))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xform = Transform(uid);
|
||||||
|
var indices = _xform.GetGridOrMapTilePosition(uid, xform);
|
||||||
|
|
||||||
|
sMcomponent.DamageUpdateAccumulator += frameTime;
|
||||||
|
sMcomponent.YellAccumulator += frameTime;
|
||||||
|
|
||||||
|
if (!(sMcomponent.DamageUpdateAccumulator > sMcomponent.DamageUpdateTimer))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sMcomponent.DamageArchived = sMcomponent.Damage;
|
||||||
|
//we're in space or there is no gas to process
|
||||||
|
if (!xform.GridUid.HasValue || mixture is null || mixture.TotalMoles == 0f)
|
||||||
|
{
|
||||||
|
sMcomponent.Damage += Math.Max(sMcomponent.Power / 1000 * sMcomponent.DamageIncreaseMultiplier, 0.1f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Absorbed gas from surrounding area
|
||||||
|
var absorbedGas = mixture.Remove(sMcomponent.GasEfficiency * mixture.TotalMoles);
|
||||||
|
var absorbedTotalMoles = absorbedGas.TotalMoles;
|
||||||
|
|
||||||
|
//Mols start to have a positive effect on damage after 350
|
||||||
|
sMcomponent.Damage = (float) Math.Max(
|
||||||
|
sMcomponent.Damage + Math.Max(
|
||||||
|
Math.Clamp(absorbedTotalMoles / 200, 0.5, 1) * absorbedGas.Temperature -
|
||||||
|
(Atmospherics.T0C + sMcomponent.HeatPenaltyThreshold) * sMcomponent.DynamicHeatResistance,
|
||||||
|
0)
|
||||||
|
* sMcomponent.MoleHeatPenalty / 150 * sMcomponent.DamageIncreaseMultiplier,
|
||||||
|
0);
|
||||||
|
|
||||||
|
//Power only starts affecting damage when it is above 5000
|
||||||
|
sMcomponent.Damage =
|
||||||
|
Math.Max(
|
||||||
|
sMcomponent.Damage +
|
||||||
|
Math.Max(sMcomponent.Power - sMcomponent.PowerPenaltyThreshold, 0) / 500 *
|
||||||
|
sMcomponent.DamageIncreaseMultiplier, 0);
|
||||||
|
|
||||||
|
//Molar count only starts affecting damage when it is above 1800
|
||||||
|
sMcomponent.Damage =
|
||||||
|
Math.Max(
|
||||||
|
sMcomponent.Damage + Math.Max(absorbedTotalMoles - sMcomponent.MolePenaltyThreshold, 0) / 80 *
|
||||||
|
sMcomponent.DamageIncreaseMultiplier, 0);
|
||||||
|
|
||||||
|
//There might be a way to integrate healing and hurting via heat
|
||||||
|
//healing damage
|
||||||
|
if (absorbedTotalMoles < sMcomponent.MolePenaltyThreshold)
|
||||||
|
{
|
||||||
|
//Only has a net positive effect when the temp is below 313.15, heals up to 2 damage. Psycologists increase this temp min by up to 45
|
||||||
|
sMcomponent.Damage =
|
||||||
|
Math.Max(
|
||||||
|
sMcomponent.Damage +
|
||||||
|
Math.Min(absorbedGas.Temperature - (Atmospherics.T0C + sMcomponent.HeatPenaltyThreshold),
|
||||||
|
0) / 150,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if there are space tiles next to SM
|
||||||
|
//TODO: change moles out for checking if adjacent tiles exist
|
||||||
|
foreach (var ind in _atmosphere.GetAdjacentTileMixtures(xform.GridUid.Value, indices))
|
||||||
|
{
|
||||||
|
if (ind.TotalMoles != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var integrity = GetIntegrity(sMcomponent.Damage, sMcomponent.ExplosionPoint);
|
||||||
|
|
||||||
|
var factor = integrity switch
|
||||||
|
{
|
||||||
|
< 10 => 0.0005f,
|
||||||
|
< 25 => 0.0009f,
|
||||||
|
< 45 => 0.005f,
|
||||||
|
< 75 => 0.002f,
|
||||||
|
_ => 0f
|
||||||
|
};
|
||||||
|
|
||||||
|
sMcomponent.Damage += Math.Clamp(sMcomponent.Power * factor * sMcomponent.DamageIncreaseMultiplier,
|
||||||
|
0, sMcomponent.MaxSpaceExposureDamage);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sMcomponent.Damage =
|
||||||
|
Math.Min(sMcomponent.DamageArchived + sMcomponent.DamageHardcap * sMcomponent.ExplosionPoint,
|
||||||
|
sMcomponent.Damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleSoundLoop(uid, sMcomponent);
|
||||||
|
|
||||||
|
if (sMcomponent.Damage > sMcomponent.ExplosionPoint)
|
||||||
|
{
|
||||||
|
Delamination(uid, frameTime, sMcomponent, xplode, mixture);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sMcomponent.Damage > sMcomponent.WarningPoint)
|
||||||
|
{
|
||||||
|
var integrity = GetIntegrity(sMcomponent.Damage, sMcomponent.ExplosionPoint);
|
||||||
|
if (sMcomponent.YellAccumulator >= sMcomponent.YellTimer)
|
||||||
|
{
|
||||||
|
if (sMcomponent.Damage > sMcomponent.EmergencyPoint)
|
||||||
|
{
|
||||||
|
_chat.TrySendInGameICMessage(uid,
|
||||||
|
Loc.GetString("supermatter-danger-message", ("integrity", integrity.ToString("0.00"))),
|
||||||
|
InGameICChatType.Speak, hideChat: true);
|
||||||
|
}
|
||||||
|
else if (sMcomponent.Damage >= sMcomponent.DamageArchived)
|
||||||
|
{
|
||||||
|
_chat.TrySendInGameICMessage(uid,
|
||||||
|
Loc.GetString("supermatter-warning-message", ("integrity", integrity.ToString("0.00"))),
|
||||||
|
InGameICChatType.Speak, hideChat: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_chat.TrySendInGameICMessage(uid,
|
||||||
|
Loc.GetString("supermatter-safe-alert", ("integrity", integrity.ToString("0.00"))),
|
||||||
|
InGameICChatType.Speak, hideChat: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
sMcomponent.YellAccumulator = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sMcomponent.DamageUpdateAccumulator -= sMcomponent.DamageUpdateTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetIntegrity(float damage, float explosionPoint)
|
||||||
|
{
|
||||||
|
var integrity = damage / explosionPoint;
|
||||||
|
integrity = (float) Math.Round(100 - integrity * 100, 2);
|
||||||
|
integrity = integrity < 0 ? 0 : integrity;
|
||||||
|
return integrity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs the logic and timers for Delamination
|
||||||
|
/// </summary>
|
||||||
|
private void Delamination(
|
||||||
|
EntityUid uid,
|
||||||
|
float frameTime,
|
||||||
|
SupermatterComponent? sMcomponent = null,
|
||||||
|
ExplosiveComponent? xplode = null,
|
||||||
|
Atmos.GasMixture? mixture = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref sMcomponent, ref xplode))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xform = Transform(uid);
|
||||||
|
|
||||||
|
//before we actually start counting down, check to see what delam type we're doing.
|
||||||
|
if (!sMcomponent.FinalCountdown)
|
||||||
|
{
|
||||||
|
//if we're in atmos
|
||||||
|
if (mixture is { })
|
||||||
|
{
|
||||||
|
//Absorbed gas from surrounding area
|
||||||
|
var absorbedGas = mixture.Remove(sMcomponent.GasEfficiency * mixture.TotalMoles);
|
||||||
|
var absorbedTotalMoles = absorbedGas.TotalMoles;
|
||||||
|
//if the moles on the sm's tile are above MolePenaltyThreshold
|
||||||
|
if (absorbedTotalMoles >= sMcomponent.MolePenaltyThreshold)
|
||||||
|
{
|
||||||
|
sMcomponent.DelamType = DelamType.Singulo;
|
||||||
|
_chat.TrySendInGameICMessage(uid, Loc.GetString("supermatter-delamination-overmass"),
|
||||||
|
InGameICChatType.Speak, hideChat: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sMcomponent.DelamType = DelamType.Explosion;
|
||||||
|
_chat.TrySendInGameICMessage(uid, Loc.GetString("supermatter-delamination-default"),
|
||||||
|
InGameICChatType.Speak, hideChat: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sMcomponent.FinalCountdown = true;
|
||||||
|
|
||||||
|
sMcomponent.DelamTimerAccumulator += frameTime;
|
||||||
|
sMcomponent.SpeakAccumulator += frameTime;
|
||||||
|
var roundSeconds = sMcomponent.DelamTimerTimer - (int) Math.Floor(sMcomponent.DelamTimerAccumulator);
|
||||||
|
|
||||||
|
//we're more than 5 seconds from delam, only yell every 5 seconds.
|
||||||
|
if (roundSeconds >= sMcomponent.YellDelam && sMcomponent.SpeakAccumulator >= sMcomponent.YellDelam)
|
||||||
|
{
|
||||||
|
sMcomponent.SpeakAccumulator -= sMcomponent.YellDelam;
|
||||||
|
_chat.TrySendInGameICMessage(uid,
|
||||||
|
Loc.GetString("supermatter-seconds-before-delam", ("Seconds", roundSeconds)),
|
||||||
|
InGameICChatType.Speak, hideChat: true);
|
||||||
|
}
|
||||||
|
//less than 5 seconds to delam, count every second.
|
||||||
|
else if (roundSeconds < sMcomponent.YellDelam && sMcomponent.SpeakAccumulator >= 1)
|
||||||
|
{
|
||||||
|
sMcomponent.SpeakAccumulator -= 1;
|
||||||
|
_chat.TrySendInGameICMessage(uid,
|
||||||
|
Loc.GetString("supermatter-seconds-before-delam", ("Seconds", roundSeconds)),
|
||||||
|
InGameICChatType.Speak, hideChat: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: make tesla(?) spawn at SupermatterComponent.PowerPenaltyThreshold and think up other delam types
|
||||||
|
//times up, explode or make a singulo
|
||||||
|
if (!(sMcomponent.DelamTimerAccumulator >= sMcomponent.DelamTimerTimer))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sMcomponent.DelamType == DelamType.Singulo)
|
||||||
|
{
|
||||||
|
//spawn a singulo :)
|
||||||
|
var singuloEntity = EntityManager.SpawnEntity("Singularity", xform.Coordinates);
|
||||||
|
_singularity.SetLevel(singuloEntity, 4);
|
||||||
|
|
||||||
|
_explosion.TriggerExplosive(
|
||||||
|
uid,
|
||||||
|
explosive: xplode,
|
||||||
|
totalIntensity: sMcomponent.TotalIntensity / 50,
|
||||||
|
radius: sMcomponent.Radius / 50,
|
||||||
|
user: uid
|
||||||
|
);
|
||||||
|
|
||||||
|
_audio.Stop(sMcomponent.AudioEntity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//explosion!!!!!
|
||||||
|
_explosion.TriggerExplosive(
|
||||||
|
uid,
|
||||||
|
explosive: xplode,
|
||||||
|
totalIntensity: sMcomponent.TotalIntensity,
|
||||||
|
radius: sMcomponent.Radius,
|
||||||
|
user: uid
|
||||||
|
);
|
||||||
|
|
||||||
|
_audio.Stop(sMcomponent.AudioEntity);
|
||||||
|
_ambient.SetAmbience(uid, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
sMcomponent.FinalCountdown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleSoundLoop(EntityUid uid, SupermatterComponent sMcomponent)
|
||||||
|
{
|
||||||
|
var isAggressive = sMcomponent.Damage > sMcomponent.WarningPoint;
|
||||||
|
var isDelamming = sMcomponent.Damage > sMcomponent.ExplosionPoint;
|
||||||
|
|
||||||
|
if (!isAggressive && !isDelamming)
|
||||||
|
{
|
||||||
|
_audio.Stop(sMcomponent.AudioEntity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var smSound = isDelamming ? SuperMatterSound.Delam : SuperMatterSound.Aggressive;
|
||||||
|
|
||||||
|
if (sMcomponent.SmSound == smSound)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_audio.Stop(sMcomponent.AudioEntity);
|
||||||
|
|
||||||
|
var sounds = isDelamming ? sMcomponent.DelamAlarm : sMcomponent.DelamSound;
|
||||||
|
var sound = _audio.GetSound(sounds);
|
||||||
|
var param = sounds.Params.WithLoop(true).WithVolume(5f).WithMaxDistance(20f);
|
||||||
|
sMcomponent.AudioEntity = _audio.PlayPvs(sound, uid, param).Value.Entity;
|
||||||
|
sMcomponent.SmSound = smSound;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if an entity can be dusted
|
||||||
|
/// </summary>
|
||||||
|
private bool CannotDestroy(EntityUid uid)
|
||||||
|
{
|
||||||
|
var @static = false;
|
||||||
|
|
||||||
|
var tag = _tag.HasTag(uid, "SMImmune");
|
||||||
|
|
||||||
|
if (EntityManager.TryGetComponent<PhysicsComponent>(uid, out var physicsComp))
|
||||||
|
{
|
||||||
|
@static = physicsComp.BodyType == BodyType.Static;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag || @static;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCollideEvent(EntityUid uid, SupermatterComponent supermatter, ref StartCollideEvent args)
|
||||||
|
{
|
||||||
|
var target = args.OtherBody.Owner;
|
||||||
|
|
||||||
|
if (!supermatter.Whitelist.IsValid(target) || CannotDestroy(target) || _container.IsEntityInContainer(uid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (EntityManager.TryGetComponent<SupermatterFoodComponent>(target, out var supermatterFood))
|
||||||
|
supermatter.Power += supermatterFood.Energy;
|
||||||
|
else if (EntityManager.TryGetComponent<ProjectileComponent>(target, out var projectile))
|
||||||
|
supermatter.Power += (float) projectile.Damage.Total;
|
||||||
|
else
|
||||||
|
supermatter.Power++;
|
||||||
|
|
||||||
|
supermatter.MatterPower += EntityManager.HasComponent<MobStateComponent>(target) ? 200 : 0;
|
||||||
|
if (!EntityManager.HasComponent<ProjectileComponent>(target))
|
||||||
|
{
|
||||||
|
EntityManager.SpawnEntity("Ash", Transform(target).Coordinates);
|
||||||
|
_audio.PlayPvs(supermatter.DustSound, uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityManager.QueueDeleteEntity(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHandInteract(EntityUid uid, SupermatterComponent supermatter, InteractHandEvent args)
|
||||||
|
{
|
||||||
|
var target = args.User;
|
||||||
|
if (_tag.HasTag(target, "SMImmune"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
supermatter.MatterPower += 200;
|
||||||
|
EntityManager.SpawnEntity("Ash", Transform(target).Coordinates);
|
||||||
|
_audio.PlayPvs(supermatter.DustSound, uid);
|
||||||
|
EntityManager.QueueDeleteEntity(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.White.Supermatter.Systems;
|
||||||
|
using Content.Shared.Whitelist;
|
||||||
|
|
||||||
|
namespace Content.Shared.White.Supermatter.Components;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class SupermatterComponent : Component
|
||||||
|
{
|
||||||
|
#region SM Base
|
||||||
|
|
||||||
|
[DataField("whitelist")] public EntityWhitelist Whitelist = new();
|
||||||
|
public string IdTag = "EmitterBolt";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("power")]
|
||||||
|
public float Power;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of damage we have currently
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("damage")]
|
||||||
|
public float Damage = 0f;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("matterPower")]
|
||||||
|
public float MatterPower;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("matterPowerConversion")]
|
||||||
|
public float MatterPowerConversion = 10f;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public SharedSupermatterSystem.DelamType DelamType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The portion of the gasmix we're on
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("gasEfficiency")]
|
||||||
|
public float GasEfficiency = 0.15f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of heat we apply scaled
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("heatThreshold")]
|
||||||
|
public float HeatThreshold = 2500f;
|
||||||
|
|
||||||
|
#endregion SM Base
|
||||||
|
|
||||||
|
#region SM Sound
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current stream of SM audio.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid? AudioEntity;
|
||||||
|
|
||||||
|
public SharedSupermatterSystem.SuperMatterSound? SmSound;
|
||||||
|
|
||||||
|
[DataField("dustSound")]
|
||||||
|
public SoundSpecifier DustSound = new SoundPathSpecifier("/Audio/White/Supermatter/dust.ogg");
|
||||||
|
|
||||||
|
[DataField("delamSound")]
|
||||||
|
public SoundSpecifier DelamSound = new SoundPathSpecifier("/Audio/White/Supermatter/delamming.ogg");
|
||||||
|
|
||||||
|
[DataField("delamAlarm")]
|
||||||
|
public SoundSpecifier DelamAlarm = new SoundPathSpecifier("/Audio/Machines/alarm.ogg");
|
||||||
|
|
||||||
|
#endregion SM Sound
|
||||||
|
|
||||||
|
#region SM Calculation
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Based on co2 percentage, slowly moves between
|
||||||
|
/// 0 and 1. We use it to calc the powerloss_inhibitor
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("powerlossdynamicScaling")]
|
||||||
|
public float PowerlossDynamicScaling;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Affects the amount of damage and minimum point
|
||||||
|
/// at which the sm takes heat damage
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("dynamicheatResistance")]
|
||||||
|
public float DynamicHeatResistance = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to increase or lessen the amount of damage the sm takes
|
||||||
|
/// from heat based on molar counts.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("moleheatPenalty")]
|
||||||
|
public float MoleHeatPenalty = 350f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Higher == more overall power
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("reactionpowerModefier")]
|
||||||
|
public float ReactionPowerModefier = 0.55f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Higher == less heat released during reaction
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("thermalreleaseModifier")]
|
||||||
|
public float ThermalReleaseModifier = 5f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Higher == less plasma released by reaction
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("plasmareleaseModifier")]
|
||||||
|
public float PlasmaReleaseModifier = 750f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Higher == less oxygen released at high temperature/power
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("oxygenreleaseModifier")]
|
||||||
|
public float OxygenReleaseModifier = 325f;
|
||||||
|
|
||||||
|
#endregion SM Calculation
|
||||||
|
|
||||||
|
#region SM Timer
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The point at which we should start sending messeges
|
||||||
|
/// about the damage to the engi channels.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("WarningPoint")]
|
||||||
|
public float WarningPoint = 50;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The point at which we start sending messages to the common channel
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("emergencyPoint")]
|
||||||
|
public float EmergencyPoint = 500;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// we yell if over 50 damage every YellTimer Seconds
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("yellTimer")]
|
||||||
|
public float YellTimer = 30f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// set to YellTimer at first so it doesnt yell a minute after being hit
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("yellAccumulator")]
|
||||||
|
public float YellAccumulator = 30f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// YellTimer before the SM is about the delam
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("yellDelam")]
|
||||||
|
public float YellDelam = 5f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Timer for Damage
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("damageupdateAccumulator")]
|
||||||
|
public float DamageUpdateAccumulator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// update environment damage every 1 second
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("damageupdateTimer")]
|
||||||
|
public float DamageUpdateTimer = 1f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Timer for delam
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("delamtimerAccumulator")]
|
||||||
|
public float DelamTimerAccumulator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// updates delam
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("delamtimerTimer")]
|
||||||
|
public int DelamTimerTimer = 30;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The message timer
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("speakaccumulator")]
|
||||||
|
public float SpeakAccumulator = 5f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Atmos update timer
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("atmosupdateAccumulator")]
|
||||||
|
public float AtmosUpdateAccumulator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// update atmos every 1 second
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("atmosupdateTimer")]
|
||||||
|
public float AtmosUpdateTimer = 1f;
|
||||||
|
|
||||||
|
#endregion SM Timer
|
||||||
|
|
||||||
|
#region SM Threshold
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Higher == Higher percentage of inhibitor gas needed
|
||||||
|
/// before the charge inertia chain reaction effect starts.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("powerlossinhibitiongasThreshold")]
|
||||||
|
public float PowerlossInhibitionGasThreshold = 0.20f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Higher == More moles of the gas are needed before the charge
|
||||||
|
/// inertia chain reaction effect starts.
|
||||||
|
/// Scales powerloss inhibition down until this amount of moles is reached
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("powerlossinhibitionmoleThreshold")]
|
||||||
|
public float PowerlossInhibitionMoleThreshold = 20f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// bonus powerloss inhibition boost if this amount of moles is reached
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("powerlossinhibitionmoleboostThreshold")]
|
||||||
|
public float PowerlossInhibitionMoleBoostThreshold = 500f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Above this value we can get lord singulo and independent mol damage,
|
||||||
|
/// below it we can heal damage
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("molepenaltyThreshold")]
|
||||||
|
public float MolePenaltyThreshold = 1800f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// more moles of gases are harder to heat than fewer,
|
||||||
|
/// so let's scale heat damage around them
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("moleheatpenaltyThreshold")]
|
||||||
|
public float MoleHeatPenaltyThreshold;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The cutoff on power properly doing damage, pulling shit around,
|
||||||
|
/// and delamming into a tesla. Low chance of pyro anomalies, +2 bolts of electricity
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("powerPenaltyThreshold")]
|
||||||
|
public float PowerPenaltyThreshold = 5000f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Higher == Crystal safe operational temperature is higher.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("heatpenaltyThreshold")]
|
||||||
|
public float HeatPenaltyThreshold = 40f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The damage we had before this cycle. Used to limit the damage we can take each cycle, and for safe alert
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("damagearchived")]
|
||||||
|
public float DamageArchived = 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// is multiplied by ExplosionPoint to cap
|
||||||
|
/// evironmental damage per cycle
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("damageHardcap")]
|
||||||
|
public float DamageHardcap = 0.002f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// environmental damage is scaled by this
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("damageincreaseMultiplier")]
|
||||||
|
public float DamageIncreaseMultiplier = 0.25f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// if spaced sm wont take more than 2 damage per cycle
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("maxspaceexposureDamage")]
|
||||||
|
public float MaxSpaceExposureDamage = 2;
|
||||||
|
|
||||||
|
#endregion SM Threshold
|
||||||
|
|
||||||
|
#region SM Delamm
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The point at which we delamm
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("explosionPoint")]
|
||||||
|
public int ExplosionPoint = 900;
|
||||||
|
|
||||||
|
//Are we delamming?
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)] public bool Delamming = false;
|
||||||
|
|
||||||
|
//it's the final countdown
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)] public bool FinalCountdown = false;
|
||||||
|
|
||||||
|
//Explosion totalIntensity value
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("totalIntensity")]
|
||||||
|
public float TotalIntensity= 500000f;
|
||||||
|
|
||||||
|
//Explosion radius value
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("radius")]
|
||||||
|
public float Radius = 500f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// These would be what you would get at point blank, decreases with distance
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("detonationRads")]
|
||||||
|
public float DetonationRads = 200f;
|
||||||
|
|
||||||
|
#endregion SM Delamm
|
||||||
|
|
||||||
|
#region SM Gas
|
||||||
|
/// <summary>
|
||||||
|
/// Is used to store gas
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
[DataField("gasStorage")]
|
||||||
|
public Dictionary<Gas, float> GasStorage = new()
|
||||||
|
{
|
||||||
|
{Gas.Oxygen, 0f},
|
||||||
|
{Gas.Nitrogen, 0f},
|
||||||
|
{Gas.CarbonDioxide, 0f},
|
||||||
|
{Gas.Plasma, 0f},
|
||||||
|
{Gas.Tritium, 0f},
|
||||||
|
{Gas.WaterVapor, 0f}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores each gases calculation
|
||||||
|
/// </summary>
|
||||||
|
public readonly Dictionary<Gas, (float TransmitModifier, float HeatPenalty, float PowerMixRatio)> GasDataFields = new()
|
||||||
|
{
|
||||||
|
[Gas.Oxygen] = (TransmitModifier: 1.5f, HeatPenalty: 1f, PowerMixRatio: 1f),
|
||||||
|
[Gas.Nitrogen] = (TransmitModifier: 0f, HeatPenalty: -1.5f, PowerMixRatio: -1f),
|
||||||
|
[Gas.CarbonDioxide] = (TransmitModifier: 0f, HeatPenalty: 0.1f, PowerMixRatio: 1f),
|
||||||
|
[Gas.Plasma] = (TransmitModifier: 4f, HeatPenalty: 15f, PowerMixRatio: 1f),
|
||||||
|
[Gas.Tritium] = (TransmitModifier: 30f, HeatPenalty: 10f, PowerMixRatio: 1f),
|
||||||
|
[Gas.WaterVapor] = (TransmitModifier: 2f, HeatPenalty: 12f, PowerMixRatio: 1f)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endregion SM Gas
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Content.Shared.White.Supermatter.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class SupermatterFoodComponent : Component
|
||||||
|
{
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("energy")]
|
||||||
|
public int Energy { get; set; } = 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using Content.Shared.White.Supermatter.Components;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.White.Supermatter.Systems;
|
||||||
|
|
||||||
|
public abstract class SharedSupermatterSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<SupermatterComponent, ComponentStartup>(OnSupermatterStartup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SuperMatterSound : sbyte
|
||||||
|
{
|
||||||
|
Aggressive = 0,
|
||||||
|
Delam = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DelamType : sbyte
|
||||||
|
{
|
||||||
|
Explosion = 0,
|
||||||
|
Singulo = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSupermatterStartup(EntityUid uid, SupermatterComponent comp, ComponentStartup args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A state wrapper used to sync the supermatter between the server and client.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
protected sealed class SupermatterComponentState : ComponentState
|
||||||
|
{
|
||||||
|
public SupermatterComponentState(SupermatterComponent supermatter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Resources/Audio/White/Supermatter/calm.ogg
Normal file
BIN
Resources/Audio/White/Supermatter/calm.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/White/Supermatter/delamming.ogg
Normal file
BIN
Resources/Audio/White/Supermatter/delamming.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/White/Supermatter/dust.ogg
Normal file
BIN
Resources/Audio/White/Supermatter/dust.ogg
Normal file
Binary file not shown.
@@ -12,6 +12,7 @@
|
|||||||
- CanPilot
|
- CanPilot
|
||||||
- BypassInteractionRangeChecks
|
- BypassInteractionRangeChecks
|
||||||
- BypassDropChecks
|
- BypassDropChecks
|
||||||
|
- SMImmune
|
||||||
- type: Input
|
- type: Input
|
||||||
context: "aghost"
|
context: "aghost"
|
||||||
- type: Ghost
|
- type: Ghost
|
||||||
|
|||||||
@@ -245,7 +245,6 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Tanks/plasma.rsi
|
sprite: Objects/Tanks/plasma.rsi
|
||||||
- type: Item
|
- type: Item
|
||||||
size: 25
|
|
||||||
sprite: Objects/Tanks/plasma.rsi
|
sprite: Objects/Tanks/plasma.rsi
|
||||||
- type: GasTank
|
- type: GasTank
|
||||||
outputPressure: 101.3
|
outputPressure: 101.3
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
# soundHit: Waiting on serv3
|
# soundHit: Waiting on serv3
|
||||||
damage:
|
damage:
|
||||||
types:
|
types:
|
||||||
Heat: 14
|
Heat: 50
|
||||||
# mining laser real
|
# mining laser real
|
||||||
- type: GatheringProjectile
|
- type: GatheringProjectile
|
||||||
- type: Tag
|
- type: Tag
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
- type: entity
|
||||||
|
id: supermatter
|
||||||
|
name: Supermatter
|
||||||
|
description: A strangely translucent and iridescent crystal.
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Supermatter
|
||||||
|
whitelist:
|
||||||
|
tags:
|
||||||
|
- EmitterBolt
|
||||||
|
components:
|
||||||
|
- Body
|
||||||
|
- Item
|
||||||
|
- type: RadiationSource
|
||||||
|
- type: AmbientSound
|
||||||
|
range: 5
|
||||||
|
volume: 50
|
||||||
|
sound:
|
||||||
|
path: /Audio/White/Supermatter/calm.ogg
|
||||||
|
- type: Physics
|
||||||
|
bodyType: Dynamic
|
||||||
|
- type: Speech
|
||||||
|
speechSounds: Pai
|
||||||
|
- type: Fixtures
|
||||||
|
fixtures:
|
||||||
|
fix1:
|
||||||
|
shape:
|
||||||
|
!type:PhysShapeAabb
|
||||||
|
bounds: "-0.25,-0.25,0.25,0.25"
|
||||||
|
mask:
|
||||||
|
- Impassable
|
||||||
|
- MidImpassable
|
||||||
|
- HighImpassable
|
||||||
|
- LowImpassable
|
||||||
|
- InteractImpassable
|
||||||
|
- Opaque
|
||||||
|
layer:
|
||||||
|
- MidImpassable
|
||||||
|
- HighImpassable
|
||||||
|
- BulletImpassable
|
||||||
|
- InteractImpassable
|
||||||
|
- type: Transform
|
||||||
|
anchored: true
|
||||||
|
noRot: true
|
||||||
|
- type: CollisionWake
|
||||||
|
enabled: false
|
||||||
|
- type: Clickable
|
||||||
|
- type: InteractionOutline
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: WallMountedItems
|
||||||
|
sprite: White/Structures/supermatter.rsi
|
||||||
|
state: supermatter
|
||||||
|
- type: Icon
|
||||||
|
sprite: White/Structures/supermatter.rsi
|
||||||
|
state: supermatter
|
||||||
|
- type: PointLight
|
||||||
|
enabled: true
|
||||||
|
radius: 10
|
||||||
|
energy: 5
|
||||||
|
color: "#d9ce00"
|
||||||
|
- type: Explosive
|
||||||
|
explosionType: Supermatter
|
||||||
|
maxIntensity: 10000
|
||||||
|
intensitySlope: 10
|
||||||
|
totalIntensity: 10000
|
||||||
@@ -6,3 +6,6 @@
|
|||||||
|
|
||||||
- type: Tag
|
- type: Tag
|
||||||
id: CrossbowBolt
|
id: CrossbowBolt
|
||||||
|
|
||||||
|
- type: Tag
|
||||||
|
id: SMImmune
|
||||||
|
|||||||
@@ -117,3 +117,20 @@
|
|||||||
lightColor: Orange
|
lightColor: Orange
|
||||||
texturePath: /Textures/Effects/fire.rsi
|
texturePath: /Textures/Effects/fire.rsi
|
||||||
fireStates: 6
|
fireStates: 6
|
||||||
|
|
||||||
|
# WD ADDED
|
||||||
|
- type: explosion
|
||||||
|
id: Supermatter
|
||||||
|
damagePerIntensity:
|
||||||
|
types:
|
||||||
|
Radiation: 5
|
||||||
|
Heat: 4
|
||||||
|
Blunt: 3
|
||||||
|
Piercing: 3
|
||||||
|
tileBreakChance: [0, 0.5, 1]
|
||||||
|
tileBreakIntensity: [0, 10, 30]
|
||||||
|
tileBreakRerollReduction: 20
|
||||||
|
lightColor: Yellow
|
||||||
|
fireColor: Green
|
||||||
|
texturePath: /Textures/Effects/fire_greyscale.rsi
|
||||||
|
fireStates: 3
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"copyright": "Taken from https://github.com/tgstation/tgstation/blob/master/icons/obj/supermatter.dmi",
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 48
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "supermatter"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
Reference in New Issue
Block a user