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
|
||||
- BypassInteractionRangeChecks
|
||||
- BypassDropChecks
|
||||
- SMImmune
|
||||
- type: Input
|
||||
context: "aghost"
|
||||
- type: Ghost
|
||||
|
||||
@@ -245,7 +245,6 @@
|
||||
- type: Sprite
|
||||
sprite: Objects/Tanks/plasma.rsi
|
||||
- type: Item
|
||||
size: 25
|
||||
sprite: Objects/Tanks/plasma.rsi
|
||||
- type: GasTank
|
||||
outputPressure: 101.3
|
||||
|
||||
@@ -306,7 +306,7 @@
|
||||
# soundHit: Waiting on serv3
|
||||
damage:
|
||||
types:
|
||||
Heat: 14
|
||||
Heat: 50
|
||||
# mining laser real
|
||||
- type: GatheringProjectile
|
||||
- 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
|
||||
id: CrossbowBolt
|
||||
|
||||
- type: Tag
|
||||
id: SMImmune
|
||||
|
||||
@@ -117,3 +117,20 @@
|
||||
lightColor: Orange
|
||||
texturePath: /Textures/Effects/fire.rsi
|
||||
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