Liquid anomaly (#20626)
Co-authored-by: Kara <lunarautomaton6@gmail.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
using Content.Server.Anomaly.Effects;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Server.Anomaly.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows the anomaly to inject liquid from the SolutionContainer
|
||||||
|
/// into the surrounding entities with the InjectionSolution component
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
[RegisterComponent, Access(typeof(InjectionAnomalySystem))]
|
||||||
|
public sealed partial class InjectionAnomalyComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// the maximum amount of injection of a substance into an entity per pulsation
|
||||||
|
/// scales with Severity
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float MaxSolutionInjection = 15;
|
||||||
|
/// <summary>
|
||||||
|
/// the maximum amount of injection of a substance into an entity in the supercritical phase
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float SuperCriticalSolutionInjection = 50;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum radius in which the anomaly injects reagents into the surrounding containers.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float InjectRadius = 3;
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum radius in which the anomaly injects reagents into the surrounding containers.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float SuperCriticalInjectRadius = 15;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the prototype of the special effect that appears above the entities into which the injection was carried out
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
public EntProtoId VisualEffectPrototype = "PuddleSparkle";
|
||||||
|
/// <summary>
|
||||||
|
/// Solution name that can be drained.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public string Solution { get; set; } = "default";
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Content.Server.Anomaly.Effects;
|
||||||
|
|
||||||
|
namespace Content.Server.Anomaly.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows the anomaly to create puddles from the solutionContainer
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, Access(typeof(PuddleCreateAnomalySystem))]
|
||||||
|
public sealed partial class PuddleCreateAnomalyComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum amount of solution that an anomaly can splash out of the storage on the floor during pulsation.
|
||||||
|
/// Scales with Severity.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float MaxPuddleSize = 100;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum amount of solution that an anomaly can splash out of the storage on the floor during supercritical event
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float SuperCriticalPuddleSize = 1000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Solution name that can be drained.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public string Solution { get; set; } = "default";
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
using Content.Server.Anomaly.Effects;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace Content.Server.Anomaly.Components;
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows the anomaly to generate a random type of reagent in the specified SolutionContainer.
|
||||||
|
/// With the increasing severity of the anomaly, the type of reagent produced may change.
|
||||||
|
/// The higher the severity of the anomaly, the higher the chance of dangerous or useful reagents.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, Access(typeof(ReagentProducerAnomalySystem))]
|
||||||
|
public sealed partial class ReagentProducerAnomalyComponent : Component
|
||||||
|
{
|
||||||
|
//the addition of the reagent will occur instantly when an anomaly appears,
|
||||||
|
//and there will not be the first three seconds of a white empty anomaly.
|
||||||
|
public float AccumulatedFrametime = 3.0f;
|
||||||
|
/// <summary>
|
||||||
|
/// How frequently should this reagent generation update, in seconds?
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float UpdateInterval = 3.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The spread of the random weight of the choice of this category, depending on the severity.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public Vector2 WeightSpreadDangerous = new(5.0f, 9.0f);
|
||||||
|
/// <summary>
|
||||||
|
/// The spread of the random weight of the choice of this category, depending on the severity.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public Vector2 WeightSpreadFun = new(3.0f, 0.0f);
|
||||||
|
/// <summary>
|
||||||
|
/// The spread of the random weight of the choice of this category, depending on the severity.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public Vector2 WeightSpreadUseful = new(1.0f, 1.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Category of dangerous reagents for injection. Various toxins and poisons
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public List<ProtoId<ReagentPrototype>> DangerousChemicals = new();
|
||||||
|
/// <summary>
|
||||||
|
/// Category of useful reagents for injection. Medicine and other things that players WANT to get
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public List<ProtoId<ReagentPrototype>> UsefulChemicals = new();
|
||||||
|
/// <summary>
|
||||||
|
/// Category of fun reagents for injection. Glue, drugs, beer. Something that will bring fun.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public List<ProtoId<ReagentPrototype>> FunChemicals = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Noise made when anomaly pulse.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public SoundSpecifier ChangeSound = new SoundPathSpecifier("/Audio/Effects/waterswirl.ogg");
|
||||||
|
/// <summary>
|
||||||
|
/// The component will repaint the sprites of the object to match the current color of the solution,
|
||||||
|
/// if the RandomSprite component is hung correctly.
|
||||||
|
/// Ideally, this should be put into a separate component, but I suffered for 4 hours,
|
||||||
|
/// and nothing worked out for me. So for now it will be like this.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
public bool NeedRecolor = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// the maximum amount of reagent produced per second
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float MaxReagentProducing = 1.5f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// how much does the reagent production increase before entering the supercritical state
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float SupercriticalReagentProducingModifier = 100f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the reagent that the anomaly produces.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public ProtoId<ReagentPrototype> ProducingReagent = "Water";
|
||||||
|
/// <summary>
|
||||||
|
/// Solution name where the substance is generated
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("solution")]
|
||||||
|
public string Solution = "default";
|
||||||
|
}
|
||||||
67
Content.Server/Anomaly/Effects/InjectionAnomalySystem.cs
Normal file
67
Content.Server/Anomaly/Effects/InjectionAnomalySystem.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Content.Server.Anomaly.Components;
|
||||||
|
using Content.Server.Chemistry.Components.SolutionManager;
|
||||||
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
|
using Content.Shared.Anomaly.Components;
|
||||||
|
|
||||||
|
namespace Content.Server.Anomaly.Effects;
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows the anomaly to inject liquid from the SolutionContainer
|
||||||
|
/// into the surrounding entities with the InjectionSolution component
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
|
|
||||||
|
/// <see cref="InjectionAnomalyComponent"/>
|
||||||
|
public sealed class InjectionAnomalySystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
|
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
|
||||||
|
|
||||||
|
private EntityQuery<InjectableSolutionComponent> _injectableQuery;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<InjectionAnomalyComponent, AnomalyPulseEvent>(OnPulse);
|
||||||
|
SubscribeLocalEvent<InjectionAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical, before: new[] { typeof(SolutionContainerSystem) });
|
||||||
|
|
||||||
|
_injectableQuery = GetEntityQuery<InjectableSolutionComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPulse(EntityUid uid, InjectionAnomalyComponent component, ref AnomalyPulseEvent args)
|
||||||
|
{
|
||||||
|
PulseScalableEffect(uid, component, component.InjectRadius, component.MaxSolutionInjection * args.Severity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSupercritical(EntityUid uid, InjectionAnomalyComponent component, ref AnomalySupercriticalEvent args)
|
||||||
|
{
|
||||||
|
PulseScalableEffect(uid, component, component.SuperCriticalInjectRadius, component.SuperCriticalSolutionInjection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PulseScalableEffect(EntityUid uid, InjectionAnomalyComponent component, float injectRadius, float maxInject)
|
||||||
|
{
|
||||||
|
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol))
|
||||||
|
return;
|
||||||
|
//We get all the entity in the radius into which the reagent will be injected.
|
||||||
|
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
|
var xform = xformQuery.GetComponent(uid);
|
||||||
|
var allEnts = _lookup.GetComponentsInRange<InjectableSolutionComponent>(xform.MapPosition, injectRadius)
|
||||||
|
.Select(x => x.Owner).ToList();
|
||||||
|
|
||||||
|
//for each matching entity found
|
||||||
|
foreach (var ent in allEnts)
|
||||||
|
{
|
||||||
|
if (!_solutionContainer.TryGetInjectableSolution(ent, out var injectable))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_injectableQuery.TryGetComponent(ent, out var injEnt))
|
||||||
|
{
|
||||||
|
var buffer = sol;
|
||||||
|
_solutionContainer.TryTransferSolution(ent, injectable, buffer, maxInject);
|
||||||
|
//Spawn Effect
|
||||||
|
var uidXform = Transform(ent);
|
||||||
|
Spawn(component.VisualEffectPrototype, uidXform.Coordinates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
39
Content.Server/Anomaly/Effects/PuddleCreateAnomalySystem.cs
Normal file
39
Content.Server/Anomaly/Effects/PuddleCreateAnomalySystem.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using Content.Server.Anomaly.Components;
|
||||||
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
|
using Content.Shared.Anomaly.Components;
|
||||||
|
using Content.Server.Fluids.EntitySystems;
|
||||||
|
|
||||||
|
namespace Content.Server.Anomaly.Effects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows the anomaly to create puddles from SolutionContainer.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class PuddleCreateAnomalySystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly PuddleSystem _puddle = default!;
|
||||||
|
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<PuddleCreateAnomalyComponent, AnomalyPulseEvent>(OnPulse);
|
||||||
|
SubscribeLocalEvent<PuddleCreateAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical, before: new[] { typeof(InjectionAnomalySystem) });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPulse(EntityUid uid, PuddleCreateAnomalyComponent component, ref AnomalyPulseEvent args)
|
||||||
|
{
|
||||||
|
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var xform = Transform(uid);
|
||||||
|
var puddleSol = _solutionContainer.SplitSolution(uid, sol, component.MaxPuddleSize * args.Severity);
|
||||||
|
_puddle.TrySplashSpillAt(uid, xform.Coordinates, puddleSol, out _);
|
||||||
|
}
|
||||||
|
private void OnSupercritical(EntityUid uid, PuddleCreateAnomalyComponent component, ref AnomalySupercriticalEvent args)
|
||||||
|
{
|
||||||
|
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol))
|
||||||
|
return;
|
||||||
|
var buffer = sol;
|
||||||
|
var xform = Transform(uid);
|
||||||
|
_puddle.TrySpillAt(xform.Coordinates, buffer, out _);
|
||||||
|
}
|
||||||
|
}
|
||||||
152
Content.Server/Anomaly/Effects/ReagentProducerAnomalySystem.cs
Normal file
152
Content.Server/Anomaly/Effects/ReagentProducerAnomalySystem.cs
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
using Content.Server.Anomaly.Components;
|
||||||
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
|
using Content.Shared.Anomaly.Components;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Shared.Sprite;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.Anomaly.Effects;
|
||||||
|
|
||||||
|
/// <see cref="ReagentProducerAnomalyComponent"/>
|
||||||
|
|
||||||
|
public sealed class ReagentProducerAnomalySystem : EntitySystem
|
||||||
|
{
|
||||||
|
//The idea is to divide substances into several categories.
|
||||||
|
//The anomaly will choose one of the categories with a given chance based on severity.
|
||||||
|
//Then a random substance will be selected from the selected category.
|
||||||
|
//There are the following categories:
|
||||||
|
|
||||||
|
//Dangerous:
|
||||||
|
//selected most often. A list of substances that are extremely unpleasant for injection.
|
||||||
|
|
||||||
|
//Fun:
|
||||||
|
//Funny things have an increased chance of appearing in an anomaly.
|
||||||
|
|
||||||
|
//Useful:
|
||||||
|
//Those reagents that the players are hunting for. Very low percentage of loss.
|
||||||
|
|
||||||
|
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly PointLightSystem _light = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
|
||||||
|
public const string FallbackReagent = "Water";
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<ReagentProducerAnomalyComponent, AnomalyPulseEvent>(OnPulse);
|
||||||
|
SubscribeLocalEvent<ReagentProducerAnomalyComponent, MapInitEvent>(OnMapInit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPulse(EntityUid uid, ReagentProducerAnomalyComponent component, ref AnomalyPulseEvent args)
|
||||||
|
{
|
||||||
|
if (_random.NextFloat(0.0f, 1.0f) > args.Stability)
|
||||||
|
ChangeReagent(uid, component, args.Severity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ChangeReagent(EntityUid uid, ReagentProducerAnomalyComponent component, float severity)
|
||||||
|
{
|
||||||
|
var reagent = GetRandomReagentType(uid, component, severity);
|
||||||
|
component.ProducingReagent = reagent;
|
||||||
|
_audio.PlayPvs(component.ChangeSound, uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
//reagent realtime generation
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
var query = EntityQueryEnumerator<ReagentProducerAnomalyComponent, AnomalyComponent>();
|
||||||
|
while (query.MoveNext(out var uid, out var component, out var anomaly))
|
||||||
|
{
|
||||||
|
component.AccumulatedFrametime += frameTime;
|
||||||
|
|
||||||
|
if (component.AccumulatedFrametime < component.UpdateInterval)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var producerSol))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Solution newSol = new();
|
||||||
|
var reagentProducingAmount = anomaly.Stability * component.MaxReagentProducing * component.AccumulatedFrametime;
|
||||||
|
if (anomaly.Severity >= 0.97) reagentProducingAmount *= component.SupercriticalReagentProducingModifier;
|
||||||
|
|
||||||
|
newSol.AddReagent(component.ProducingReagent, reagentProducingAmount);
|
||||||
|
_solutionContainer.TryAddSolution(uid, producerSol, newSol); //TO DO - the container is not fully filled.
|
||||||
|
|
||||||
|
component.AccumulatedFrametime = 0;
|
||||||
|
|
||||||
|
// The component will repaint the sprites of the object to match the current color of the solution,
|
||||||
|
// if the RandomSprite component is hung correctly.
|
||||||
|
|
||||||
|
// Ideally, this should be put into a separate component, but I suffered for 4 hours,
|
||||||
|
// and nothing worked out for me. So for now it will be like this.
|
||||||
|
if (component.NeedRecolor)
|
||||||
|
{
|
||||||
|
var color = producerSol.GetColor(_prototypeManager);
|
||||||
|
_light.SetColor(uid, color);
|
||||||
|
if (TryComp<RandomSpriteComponent>(uid, out var randomSprite))
|
||||||
|
{
|
||||||
|
foreach (var ent in randomSprite.Selected)
|
||||||
|
{
|
||||||
|
var state = randomSprite.Selected[ent.Key];
|
||||||
|
state.Color = color;
|
||||||
|
randomSprite.Selected[ent.Key] = state;
|
||||||
|
}
|
||||||
|
Dirty(uid, randomSprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMapInit(EntityUid uid, ReagentProducerAnomalyComponent component, MapInitEvent args)
|
||||||
|
{
|
||||||
|
ChangeReagent(uid, component, 0.1f); //MapInit Reagent 100% change
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a random reagent based on a system of random weights.
|
||||||
|
// First, the category is selected: The category has a minimum and maximum weight,
|
||||||
|
// the current value depends on severity.
|
||||||
|
// Accordingly, with the strengthening of the anomaly,
|
||||||
|
// the chances of falling out of some categories grow, and some fall.
|
||||||
|
//
|
||||||
|
// After that, a random reagent in the selected category is selected.
|
||||||
|
//
|
||||||
|
// Such a system is made to control the danger and interest of the anomaly more.
|
||||||
|
private string GetRandomReagentType(EntityUid uid, ReagentProducerAnomalyComponent component, float severity)
|
||||||
|
{
|
||||||
|
//Category Weight Randomization
|
||||||
|
var currentWeightDangerous = MathHelper.Lerp(component.WeightSpreadDangerous.X, component.WeightSpreadDangerous.Y, severity);
|
||||||
|
var currentWeightFun = MathHelper.Lerp(component.WeightSpreadFun.X, component.WeightSpreadFun.Y, severity);
|
||||||
|
var currentWeightUseful = MathHelper.Lerp(component.WeightSpreadUseful.X, component.WeightSpreadUseful.Y, severity);
|
||||||
|
|
||||||
|
var sumWeight = currentWeightDangerous + currentWeightFun + currentWeightUseful;
|
||||||
|
var rnd = _random.NextFloat(0f, sumWeight);
|
||||||
|
//Dangerous
|
||||||
|
if (rnd <= currentWeightDangerous && component.DangerousChemicals.Count > 0)
|
||||||
|
{
|
||||||
|
var reagent = _random.Pick(component.DangerousChemicals);
|
||||||
|
return reagent;
|
||||||
|
}
|
||||||
|
else rnd -= currentWeightDangerous;
|
||||||
|
//Fun
|
||||||
|
if (rnd <= currentWeightFun && component.FunChemicals.Count > 0)
|
||||||
|
{
|
||||||
|
var reagent = _random.Pick(component.FunChemicals);
|
||||||
|
return reagent;
|
||||||
|
}
|
||||||
|
else rnd -= currentWeightFun;
|
||||||
|
//Useful
|
||||||
|
if (rnd <= currentWeightUseful && component.UsefulChemicals.Count > 0)
|
||||||
|
{
|
||||||
|
var reagent = _random.Pick(component.UsefulChemicals);
|
||||||
|
return reagent;
|
||||||
|
}
|
||||||
|
//We should never end up here.
|
||||||
|
//Maybe Log Error?
|
||||||
|
return FallbackReagent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,3 +57,8 @@
|
|||||||
license: "CC-BY-SA-3.0"
|
license: "CC-BY-SA-3.0"
|
||||||
copyright: "Taken from tgstation"
|
copyright: "Taken from tgstation"
|
||||||
source: "https://github.com/tgstation/tgstation/blob/e3a835b96043fad1269ee7b0c3a6cb340a466f3a/sound/effects/break_stone.ogg"
|
source: "https://github.com/tgstation/tgstation/blob/e3a835b96043fad1269ee7b0c3a6cb340a466f3a/sound/effects/break_stone.ogg"
|
||||||
|
|
||||||
|
- files: ["waterswirl.ogg"]
|
||||||
|
license: "CC0-1.0"
|
||||||
|
copyright: "Taken from InspectorJ via freesound.org and mixed from stereo to mono."
|
||||||
|
source: "https://freesound.org/people/InspectorJ/sounds/398703/"
|
||||||
|
|||||||
BIN
Resources/Audio/Effects/waterswirl.ogg
Normal file
BIN
Resources/Audio/Effects/waterswirl.ogg
Normal file
Binary file not shown.
@@ -17,4 +17,5 @@
|
|||||||
- AnomalyBluespace
|
- AnomalyBluespace
|
||||||
- AnomalyIce
|
- AnomalyIce
|
||||||
- AnomalyRock
|
- AnomalyRock
|
||||||
|
- AnomalyLiquid
|
||||||
chance: 1
|
chance: 1
|
||||||
|
|||||||
@@ -206,3 +206,232 @@
|
|||||||
radius: 2
|
radius: 2
|
||||||
energy: 3
|
energy: 3
|
||||||
color: "#06DF24"
|
color: "#06DF24"
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: Reagent slime
|
||||||
|
id: ReagentSlime
|
||||||
|
suffix: Water
|
||||||
|
parent: MobAdultSlimes
|
||||||
|
description: It consists of a liquid, and it wants to dissolve you in itself.
|
||||||
|
components:
|
||||||
|
- type: NpcFactionMember
|
||||||
|
factions:
|
||||||
|
- SimpleHostile
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: Mobs/Aliens/elemental.rsi
|
||||||
|
layers:
|
||||||
|
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
state: alive
|
||||||
|
color: "#75b1f0"
|
||||||
|
- type: PointLight
|
||||||
|
radius: 2.0
|
||||||
|
energy: 3.5
|
||||||
|
color: "#75b1f0" # Edited through the LiquidAnomalySystem
|
||||||
|
- type: MobState
|
||||||
|
allowedStates:
|
||||||
|
- Alive
|
||||||
|
- Dead
|
||||||
|
- type: MobThresholds
|
||||||
|
thresholds:
|
||||||
|
0: Alive
|
||||||
|
150: Dead
|
||||||
|
- type: SlowOnDamage
|
||||||
|
speedModifierThresholds:
|
||||||
|
50: 0.4
|
||||||
|
- type: Bloodstream
|
||||||
|
bloodReagent: Water
|
||||||
|
chemicalMaxVolume: 100
|
||||||
|
- type: StatusEffects
|
||||||
|
allowed:
|
||||||
|
- SlowedDown
|
||||||
|
- Electrocution
|
||||||
|
- type: MeleeWeapon
|
||||||
|
soundHit:
|
||||||
|
collection: AlienClaw
|
||||||
|
animation: WeaponArcBite
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Slash: 15
|
||||||
|
- type: MeleeChemicalInjector
|
||||||
|
solution: bloodstream
|
||||||
|
transferAmount: 5
|
||||||
|
- type: DamageStateVisuals
|
||||||
|
rotate: true
|
||||||
|
states:
|
||||||
|
Alive:
|
||||||
|
Base: alive
|
||||||
|
Dead:
|
||||||
|
Base: dead
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- FootstepSound
|
||||||
|
- CannotSuicide
|
||||||
|
- DoorBumpOpener
|
||||||
|
- type: NoSlip
|
||||||
|
- type: ZombieImmune
|
||||||
|
- type: ExaminableSolution
|
||||||
|
solution: bloodstream
|
||||||
|
- type: InjectableSolution
|
||||||
|
solution: bloodstream
|
||||||
|
- type: DrainableSolution
|
||||||
|
solution: bloodstream
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: Reagent Slime Spawner
|
||||||
|
id: ReagentSlimeSpawner
|
||||||
|
parent: MarkerBase
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: red
|
||||||
|
- sprite: Mobs/Aliens/elemental.rsi
|
||||||
|
state: alive
|
||||||
|
- type: RandomSpawner
|
||||||
|
prototypes:
|
||||||
|
- ReagentSlime
|
||||||
|
- ReagentSlimeBeer
|
||||||
|
- ReagentSlimePax
|
||||||
|
- ReagentSlimeNocturine
|
||||||
|
- ReagentSlimeTHC
|
||||||
|
- ReagentSlimeBicaridine
|
||||||
|
- ReagentSlimeToxin
|
||||||
|
- ReagentSlimeNapalm
|
||||||
|
- ReagentSlimeOmnizine
|
||||||
|
chance: 1
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ReagentSlimeBeer
|
||||||
|
parent: ReagentSlime
|
||||||
|
suffix: Beer
|
||||||
|
components:
|
||||||
|
- type: Bloodstream
|
||||||
|
bloodReagent: Beer
|
||||||
|
- type: PointLight
|
||||||
|
color: "#cfa85f"
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: Mobs/Aliens/elemental.rsi
|
||||||
|
layers:
|
||||||
|
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
state: alive
|
||||||
|
color: "#cfa85f"
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ReagentSlimePax
|
||||||
|
parent: ReagentSlime
|
||||||
|
suffix: Pax
|
||||||
|
components:
|
||||||
|
- type: Bloodstream
|
||||||
|
bloodReagent: Pax
|
||||||
|
- type: PointLight
|
||||||
|
color: "#AAAAAA"
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: Mobs/Aliens/elemental.rsi
|
||||||
|
layers:
|
||||||
|
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
state: alive
|
||||||
|
color: "#AAAAAA"
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ReagentSlimeNocturine
|
||||||
|
parent: ReagentSlime
|
||||||
|
suffix: Nocturine
|
||||||
|
components:
|
||||||
|
- type: Bloodstream
|
||||||
|
bloodReagent: Nocturine
|
||||||
|
- type: PointLight
|
||||||
|
color: "#128e80"
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: Mobs/Aliens/elemental.rsi
|
||||||
|
layers:
|
||||||
|
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
state: alive
|
||||||
|
color: "#128e80"
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ReagentSlimeTHC
|
||||||
|
parent: ReagentSlime
|
||||||
|
suffix: THC
|
||||||
|
components:
|
||||||
|
- type: Bloodstream
|
||||||
|
bloodReagent: THC
|
||||||
|
- type: PointLight
|
||||||
|
color: "#808080"
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: Mobs/Aliens/elemental.rsi
|
||||||
|
layers:
|
||||||
|
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
state: alive
|
||||||
|
color: "#808080"
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ReagentSlimeBicaridine
|
||||||
|
parent: ReagentSlime
|
||||||
|
suffix: Bicaridine
|
||||||
|
components:
|
||||||
|
- type: Bloodstream
|
||||||
|
bloodReagent: Bicaridine
|
||||||
|
- type: PointLight
|
||||||
|
color: "#ffaa00"
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: Mobs/Aliens/elemental.rsi
|
||||||
|
layers:
|
||||||
|
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
state: alive
|
||||||
|
color: "#ffaa00"
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ReagentSlimeToxin
|
||||||
|
parent: ReagentSlime
|
||||||
|
suffix: Toxin
|
||||||
|
components:
|
||||||
|
- type: Bloodstream
|
||||||
|
bloodReagent: Toxin
|
||||||
|
- type: PointLight
|
||||||
|
color: "#cf3600"
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: Mobs/Aliens/elemental.rsi
|
||||||
|
layers:
|
||||||
|
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
state: alive
|
||||||
|
color: "#cf3600"
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ReagentSlimeNapalm
|
||||||
|
parent: ReagentSlime
|
||||||
|
suffix: Napalm
|
||||||
|
components:
|
||||||
|
- type: Bloodstream
|
||||||
|
bloodReagent: Napalm
|
||||||
|
- type: PointLight
|
||||||
|
color: "#FA00AF"
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: Mobs/Aliens/elemental.rsi
|
||||||
|
layers:
|
||||||
|
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
state: alive
|
||||||
|
color: "#FA00AF"
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ReagentSlimeOmnizine
|
||||||
|
parent: ReagentSlime
|
||||||
|
suffix: Omnizine
|
||||||
|
components:
|
||||||
|
- type: Bloodstream
|
||||||
|
bloodReagent: Omnizine
|
||||||
|
- type: PointLight
|
||||||
|
color: "#fcf7f9"
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: Mobs/Aliens/elemental.rsi
|
||||||
|
layers:
|
||||||
|
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
state: alive
|
||||||
|
color: "#fcf7f9"
|
||||||
@@ -263,3 +263,109 @@
|
|||||||
superCriticalSpawns:
|
superCriticalSpawns:
|
||||||
- AsteroidRock
|
- AsteroidRock
|
||||||
- SpawnMobOreCrab
|
- SpawnMobOreCrab
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: AnomalyLiquid
|
||||||
|
parent: BaseAnomaly
|
||||||
|
suffix: Liquid
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Structures/Specific/Anomalies/liquid_anom.rsi
|
||||||
|
layers:
|
||||||
|
- state: anom
|
||||||
|
map: ["enum.AnomalyVisualLayers.Base"]
|
||||||
|
- state: pulse
|
||||||
|
map: ["enum.AnomalyVisualLayers.Animated"]
|
||||||
|
visible: false
|
||||||
|
- type: RandomSprite
|
||||||
|
selected: # Initialized layer values. Edited through the ReagentProducerAnomalySystem
|
||||||
|
enum.AnomalyVisualLayers.Base:
|
||||||
|
anom: "#ffffff"
|
||||||
|
enum.AnomalyVisualLayers.Animated:
|
||||||
|
pulse: "#ffffff"
|
||||||
|
- type: PointLight
|
||||||
|
radius: 4.0
|
||||||
|
energy: 3.5
|
||||||
|
color: "#bbbbbb"
|
||||||
|
- type: BadFood
|
||||||
|
- type: Anomaly
|
||||||
|
anomalyContactDamage:
|
||||||
|
types:
|
||||||
|
Slash: 1
|
||||||
|
- type: EntitySpawnAnomaly
|
||||||
|
superCriticalSpawns:
|
||||||
|
- ReagentSlimeSpawner
|
||||||
|
spawns:
|
||||||
|
- PuddleSparkle
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
anomaly:
|
||||||
|
maxVol: 1500
|
||||||
|
- type: PuddleCreateAnomaly
|
||||||
|
solution: anomaly
|
||||||
|
- type: InjectionAnomaly
|
||||||
|
solution: anomaly
|
||||||
|
- type: ReagentProducerAnomaly
|
||||||
|
solution: anomaly
|
||||||
|
needRecolor: true
|
||||||
|
dangerousChemicals:
|
||||||
|
- UnstableMutagen
|
||||||
|
- Mold
|
||||||
|
- PolytrinicAcid
|
||||||
|
- FerrochromicAcid
|
||||||
|
- FluorosulfuricAcid
|
||||||
|
- SulfuricAcid
|
||||||
|
- HeartbreakerToxin
|
||||||
|
- VentCrud
|
||||||
|
- UncookedAnimalProteins
|
||||||
|
- Thermite
|
||||||
|
- Napalm
|
||||||
|
- Phlogiston
|
||||||
|
- ChlorineTrifluoride
|
||||||
|
- FoamingAgent
|
||||||
|
- BuzzochloricBees
|
||||||
|
- RobustHarvest
|
||||||
|
usefulChemicals:
|
||||||
|
- Cryptobiolin
|
||||||
|
- Dylovene
|
||||||
|
- Arithrazine
|
||||||
|
- Bicaridine
|
||||||
|
- Cryoxadone
|
||||||
|
- Dermaline
|
||||||
|
- Dexalin
|
||||||
|
- DexalinPlus
|
||||||
|
- Epinephrine
|
||||||
|
- Leporazine
|
||||||
|
- Ambuzol
|
||||||
|
- Tricordrazine
|
||||||
|
- Artifexium
|
||||||
|
- Ethylredoxrazine
|
||||||
|
funChemicals:
|
||||||
|
- Desoxyephedrine
|
||||||
|
- Ephedrine
|
||||||
|
- THC
|
||||||
|
- THCOil
|
||||||
|
- SpaceDrugs
|
||||||
|
- Nocturine
|
||||||
|
- MuteToxin
|
||||||
|
- NorepinephricAcid
|
||||||
|
- Pax
|
||||||
|
- Ipecac
|
||||||
|
- Cognizine
|
||||||
|
- Beer
|
||||||
|
- SpaceGlue
|
||||||
|
- CogChamp
|
||||||
|
- Honk
|
||||||
|
- Carpetium
|
||||||
|
- type: Drink
|
||||||
|
solution: anomaly
|
||||||
|
- type: DrainableSolution
|
||||||
|
solution: anomaly
|
||||||
|
- type: DrawableSolution
|
||||||
|
solution: anomaly
|
||||||
|
- type: ExaminableSolution
|
||||||
|
solution: anomaly
|
||||||
|
- type: RefillableSolution
|
||||||
|
solution: anomaly
|
||||||
|
- type: InjectableSolution
|
||||||
|
solution: beaker
|
||||||
|
|||||||
BIN
Resources/Textures/Mobs/Aliens/elemental.rsi/alive.png
Normal file
BIN
Resources/Textures/Mobs/Aliens/elemental.rsi/alive.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
BIN
Resources/Textures/Mobs/Aliens/elemental.rsi/dead.png
Normal file
BIN
Resources/Textures/Mobs/Aliens/elemental.rsi/dead.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 510 B |
44
Resources/Textures/Mobs/Aliens/elemental.rsi/meta.json
Normal file
44
Resources/Textures/Mobs/Aliens/elemental.rsi/meta.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC0-1.0",
|
||||||
|
"copyright": "Created by TheShuEd (github) for Space Station 14.",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "dead"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alive",
|
||||||
|
"directions": 4,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC0-1.0",
|
||||||
|
"copyright": "Created by TheShuEd (github) for ss14",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "anom",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.18625,
|
||||||
|
0.18625,
|
||||||
|
0.18625,
|
||||||
|
0.18625
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pulse",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.15625,
|
||||||
|
0.15625,
|
||||||
|
0.15625,
|
||||||
|
0.15625
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
Reference in New Issue
Block a user