Turn ReagentEffects into generic EntityEffects (#28168)
* Oh the possibilities * Merge fixes * Forgot to remote LavaSystem oops * Changed EntityEffectArgs to EntityEffectBaseArgs and EntityEffectReagentArgs * Throw exception for unimplemented effectargs * Remove Json and overrideable datafields * Fix test issues * Actually fix the compiling issue * Fix comments and remove EntityEffectArgs (no longer used, replaced with EntityEffectBaseArgs)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Server.Chemistry.ReactionEffects;
|
||||
using Content.Server.EntityEffects.Effects;
|
||||
using Content.Server.Fluids.EntitySystems;
|
||||
using Content.Server.Forensics;
|
||||
using Content.Server.Popups;
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
@@ -193,8 +194,7 @@ namespace Content.Server.Body.Systems
|
||||
}
|
||||
|
||||
var actualEntity = ent.Comp2?.Body ?? solutionEntityUid.Value;
|
||||
var args = new ReagentEffectArgs(actualEntity, ent, solution, proto, mostToRemove,
|
||||
EntityManager, null, scale);
|
||||
var args = new EntityEffectReagentArgs(actualEntity, EntityManager, ent, solution, mostToRemove, proto, null, scale);
|
||||
|
||||
// do all effects, if conditions apply
|
||||
foreach (var effect in entry.Effects)
|
||||
|
||||
@@ -3,8 +3,8 @@ using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Server.Chemistry.ReagentEffectConditions;
|
||||
using Content.Server.Chemistry.ReagentEffects;
|
||||
using Content.Server.EntityEffects.EffectConditions;
|
||||
using Content.Server.EntityEffects.Effects;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Body.Components;
|
||||
@@ -13,6 +13,7 @@ using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -261,7 +262,7 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
// TODO generalize condition checks
|
||||
// this is pretty janky, but I just want to bodge a method that checks if an entity can breathe a gas mixture
|
||||
// Applying actual reaction effects require a full ReagentEffectArgs struct.
|
||||
bool CanMetabolize(ReagentEffect effect)
|
||||
bool CanMetabolize(EntityEffect effect)
|
||||
{
|
||||
if (effect.Conditions == null)
|
||||
return true;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
@@ -80,7 +80,7 @@ public partial struct SeedChemQuantity
|
||||
|
||||
// TODO reduce the number of friends to a reasonable level. Requires ECS-ing things like plant holder component.
|
||||
[Virtual, DataDefinition]
|
||||
[Access(typeof(BotanySystem), typeof(PlantHolderSystem), typeof(SeedExtractorSystem), typeof(PlantHolderComponent), typeof(ReagentEffect), typeof(MutationSystem))]
|
||||
[Access(typeof(BotanySystem), typeof(PlantHolderSystem), typeof(SeedExtractorSystem), typeof(PlantHolderComponent), typeof(EntityEffect), typeof(MutationSystem))]
|
||||
public partial class SeedData
|
||||
{
|
||||
#region Tracking
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Forensics;
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
using Content.Server.Fluids.EntitySystems;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Coordinates.Helpers;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Maps;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Chemistry.ReactionEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Basically smoke and foam reactions.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class AreaReactionEffect : ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// How many seconds will the effect stay, counting after fully spreading.
|
||||
/// </summary>
|
||||
[DataField("duration")] private float _duration = 10;
|
||||
|
||||
/// <summary>
|
||||
/// How many units of reaction for 1 smoke entity.
|
||||
/// </summary>
|
||||
[DataField] public FixedPoint2 OverflowThreshold = FixedPoint2.New(2.5);
|
||||
|
||||
/// <summary>
|
||||
/// The entity prototype that will be spawned as the effect.
|
||||
/// </summary>
|
||||
[DataField("prototypeId", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
private string _prototypeId = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Sound that will get played when this reaction effect occurs.
|
||||
/// </summary>
|
||||
[DataField("sound", required: true)] private SoundSpecifier _sound = default!;
|
||||
|
||||
public override bool ShouldLog => true;
|
||||
|
||||
protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-area-reaction",
|
||||
("duration", _duration)
|
||||
);
|
||||
|
||||
public override LogImpact LogImpact => LogImpact.High;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.Source == null)
|
||||
return;
|
||||
|
||||
var spreadAmount = (int) Math.Max(0, Math.Ceiling((args.Quantity / OverflowThreshold).Float()));
|
||||
var splitSolution = args.Source.SplitSolution(args.Source.Volume);
|
||||
var transform = args.EntityManager.GetComponent<TransformComponent>(args.SolutionEntity);
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
var mapSys = args.EntityManager.System<MapSystem>();
|
||||
var sys = args.EntityManager.System<TransformSystem>();
|
||||
var mapCoords = sys.GetMapCoordinates(args.SolutionEntity, xform: transform);
|
||||
|
||||
if (!mapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid) ||
|
||||
!mapSys.TryGetTileRef(gridUid, grid, transform.Coordinates, out var tileRef) ||
|
||||
tileRef.Tile.IsSpace())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var coords = mapSys.MapToGrid(gridUid, mapCoords);
|
||||
var ent = args.EntityManager.SpawnEntity(_prototypeId, coords.SnapToGrid());
|
||||
|
||||
var smoke = args.EntityManager.System<SmokeSystem>();
|
||||
smoke.StartSmoke(ent, splitSolution, _duration, spreadAmount);
|
||||
|
||||
var audio = args.EntityManager.System<SharedAudioSystem>();
|
||||
audio.PlayPvs(_sound, args.SolutionEntity, AudioHelpers.WithVariation(0.125f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Explosion;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Content.Server.Chemistry.ReactionEffects
|
||||
{
|
||||
[DataDefinition]
|
||||
public sealed partial class ExplosionReactionEffect : ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of explosion. Determines damage types and tile break chance scaling.
|
||||
/// </summary>
|
||||
[DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<ExplosionPrototype>))]
|
||||
[JsonIgnore]
|
||||
public string ExplosionType = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The max intensity the explosion can have at a given tile. Places an upper limit of damage and tile break
|
||||
/// chance.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[JsonIgnore]
|
||||
public float MaxIntensity = 5;
|
||||
|
||||
/// <summary>
|
||||
/// How quickly intensity drops off as you move away from the epicenter
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[JsonIgnore]
|
||||
public float IntensitySlope = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum total intensity that this chemical reaction can achieve. Basically here to prevent people
|
||||
/// from creating a nuke by collecting enough potassium and water.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A slope of 1 and MaxTotalIntensity of 100 corresponds to a radius of around 4.5 tiles.
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
[JsonIgnore]
|
||||
public float MaxTotalIntensity = 100;
|
||||
|
||||
/// <summary>
|
||||
/// The intensity of the explosion per unit reaction.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[JsonIgnore]
|
||||
public float IntensityPerUnit = 1;
|
||||
|
||||
public override bool ShouldLog => true;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-explosion-reaction-effect", ("chance", Probability));
|
||||
public override LogImpact LogImpact => LogImpact.High;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
var intensity = MathF.Min((float) args.Quantity * IntensityPerUnit, MaxTotalIntensity);
|
||||
|
||||
args.EntityManager.System<ExplosionSystem>()
|
||||
.QueueExplosion(
|
||||
args.SolutionEntity,
|
||||
ExplosionType,
|
||||
intensity,
|
||||
IntensitySlope,
|
||||
MaxIntensity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReactionEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the temperature of the solution involved with the reaction to a new value.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public sealed partial class SetSolutionTemperatureEffect : ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The temperature to set the solution to.
|
||||
/// </summary>
|
||||
[DataField("temperature", required: true)] private float _temperature;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-set-solution-temperature-effect",
|
||||
("chance", Probability), ("temperature", _temperature));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
var solution = args.Source;
|
||||
if (solution == null)
|
||||
return;
|
||||
|
||||
solution.Temperature = _temperature;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the temperature of the solution involved in the reaction.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public sealed partial class AdjustSolutionTemperatureEffect : ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The change in temperature.
|
||||
/// </summary>
|
||||
[DataField("delta", required: true)] private float _delta;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum temperature this effect can reach.
|
||||
/// </summary>
|
||||
[DataField("minTemp")] private float _minTemp = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum temperature this effect can reach.
|
||||
/// </summary>
|
||||
[DataField("maxTemp")] private float _maxTemp = float.PositiveInfinity;
|
||||
|
||||
/// <summary>
|
||||
/// If true, then scale ranges by intensity. If not, the ranges are the same regardless of reactant amount.
|
||||
/// </summary>
|
||||
[DataField("scaled")] private bool _scaled;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-adjust-solution-temperature-effect",
|
||||
("chance", Probability), ("deltasign", MathF.Sign(_delta)), ("mintemp", _minTemp), ("maxtemp", _maxTemp));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
var solution = args.Source;
|
||||
if (solution == null || solution.Volume == 0)
|
||||
return;
|
||||
|
||||
var deltaT = _scaled ? _delta * (float) args.Quantity : _delta;
|
||||
solution.Temperature = Math.Clamp(solution.Temperature + deltaT, _minTemp, _maxTemp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the thermal energy of the solution involved in the reaction.
|
||||
/// </summary>
|
||||
public sealed partial class AdjustSolutionThermalEnergyEffect : ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The change in energy.
|
||||
/// </summary>
|
||||
[DataField("delta", required: true)] private float _delta;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum temperature this effect can reach.
|
||||
/// </summary>
|
||||
[DataField("minTemp")] private float _minTemp = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum temperature this effect can reach.
|
||||
/// </summary>
|
||||
[DataField("maxTemp")] private float _maxTemp = float.PositiveInfinity;
|
||||
|
||||
/// <summary>
|
||||
/// If true, then scale ranges by intensity. If not, the ranges are the same regardless of reactant amount.
|
||||
/// </summary>
|
||||
[DataField("scaled")] private bool _scaled;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
var solution = args.Source;
|
||||
if (solution == null || solution.Volume == 0)
|
||||
return;
|
||||
|
||||
if (_delta > 0 && solution.Temperature >= _maxTemp)
|
||||
return;
|
||||
if (_delta < 0 && solution.Temperature <= _minTemp)
|
||||
return;
|
||||
|
||||
var heatCap = solution.GetHeatCapacity(null);
|
||||
var deltaT = _scaled
|
||||
? _delta / heatCap * (float) args.Quantity
|
||||
: _delta / heatCap;
|
||||
|
||||
solution.Temperature = Math.Clamp(solution.Temperature + deltaT, _minTemp, _maxTemp);
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-adjust-solution-temperature-effect",
|
||||
("chance", Probability), ("deltasign", MathF.Sign(_delta)), ("mintemp", _minTemp), ("maxtemp", _maxTemp));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffectConditions
|
||||
{
|
||||
/// <summary>
|
||||
/// Requires the solution entity to be above or below a certain temperature.
|
||||
/// Used for things like cryoxadone and pyroxadone.
|
||||
/// </summary>
|
||||
public sealed partial class Temperature : ReagentEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public float Min = 0;
|
||||
|
||||
[DataField]
|
||||
public float Max = float.PositiveInfinity;
|
||||
public override bool Condition(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent(args.SolutionEntity, out TemperatureComponent? temp))
|
||||
{
|
||||
if (temp.CurrentTemperature > Min && temp.CurrentTemperature < Max)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-body-temperature",
|
||||
("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max),
|
||||
("min", Min));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Localizations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Roles.Jobs;
|
||||
using Content.Shared.Station;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffectConditions
|
||||
{
|
||||
public sealed partial class JobCondition : ReagentEffectCondition
|
||||
{
|
||||
[DataField(required: true)] public List<ProtoId<JobPrototype>> Job;
|
||||
|
||||
public override bool Condition(ReagentEffectArgs args)
|
||||
{
|
||||
args.EntityManager.TryGetComponent<MindContainerComponent>(args.SolutionEntity, out var mindContainer);
|
||||
if (mindContainer != null && mindContainer.Mind != null)
|
||||
{
|
||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
if (args.EntityManager.TryGetComponent<JobComponent>(mindContainer?.Mind, out var comp) && prototypeManager.TryIndex(comp.Prototype, out var prototype))
|
||||
{
|
||||
foreach (var jobId in Job)
|
||||
{
|
||||
if (prototype.ID == jobId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
var localizedNames = Job.Select(jobId => prototype.Index(jobId).LocalizedName).ToList();
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-job-condition", ("job", ContentLocalizationManager.FormatListToOr(localizedNames)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffectConditions
|
||||
{
|
||||
public sealed partial class MobStateCondition : ReagentEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public MobState Mobstate = MobState.Alive;
|
||||
|
||||
public override bool Condition(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent(args.SolutionEntity, out MobStateComponent? mobState))
|
||||
{
|
||||
if (mobState.CurrentState == Mobstate)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-mob-state-condition", ("state", Mobstate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Shared.Body.Prototypes;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffectConditions
|
||||
{
|
||||
/// <summary>
|
||||
/// Requires that the metabolizing organ is or is not tagged with a certain MetabolizerType
|
||||
/// </summary>
|
||||
public sealed partial class OrganType : ReagentEffectCondition
|
||||
{
|
||||
[DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<MetabolizerTypePrototype>))]
|
||||
public string Type = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Does this condition pass when the organ has the type, or when it doesn't have the type?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool ShouldHave = true;
|
||||
|
||||
public override bool Condition(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.OrganEntity == null)
|
||||
return false;
|
||||
|
||||
return Condition(args.OrganEntity.Value, args.EntityManager);
|
||||
}
|
||||
|
||||
public bool Condition(Entity<MetabolizerComponent?> metabolizer, IEntityManager entMan)
|
||||
{
|
||||
metabolizer.Comp ??= entMan.GetComponentOrNull<MetabolizerComponent>(metabolizer.Owner);
|
||||
if (metabolizer.Comp != null
|
||||
&& metabolizer.Comp.MetabolizerTypes != null
|
||||
&& metabolizer.Comp.MetabolizerTypes.Contains(Type))
|
||||
return ShouldHave;
|
||||
return !ShouldHave;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-organ-type",
|
||||
("name", prototype.Index<MetabolizerTypePrototype>(Type).LocalizedName),
|
||||
("shouldhave", ShouldHave));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffectConditions
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for implementing reagent effects that require a certain amount of reagent before it should be applied.
|
||||
/// For instance, overdoses.
|
||||
///
|
||||
/// This can also trigger on -other- reagents, not just the one metabolizing. By default, it uses the
|
||||
/// one being metabolized.
|
||||
/// </summary>
|
||||
public sealed partial class ReagentThreshold : ReagentEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 Min = FixedPoint2.Zero;
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 Max = FixedPoint2.MaxValue;
|
||||
|
||||
// TODO use ReagentId
|
||||
[DataField]
|
||||
public string? Reagent;
|
||||
|
||||
public override bool Condition(ReagentEffectArgs args)
|
||||
{
|
||||
var reagent = Reagent ?? args.Reagent?.ID;
|
||||
if (reagent == null)
|
||||
return true; // No condition to apply.
|
||||
|
||||
var quant = FixedPoint2.Zero;
|
||||
if (args.Source != null)
|
||||
quant = args.Source.GetTotalPrototypeQuantity(reagent);
|
||||
|
||||
return quant >= Min && quant <= Max;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
ReagentPrototype? reagentProto = null;
|
||||
if (Reagent is not null)
|
||||
prototype.TryIndex(Reagent, out reagentProto);
|
||||
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-reagent-threshold",
|
||||
("reagent", reagentProto?.LocalizedName ?? Loc.GetString("reagent-effect-condition-guidebook-this-reagent")),
|
||||
("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()),
|
||||
("min", Min.Float()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffectConditions
|
||||
{
|
||||
/// <summary>
|
||||
/// Requires the solution to be above or below a certain temperature.
|
||||
/// Used for things like explosives.
|
||||
/// </summary>
|
||||
public sealed partial class SolutionTemperature : ReagentEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public float Min = 0.0f;
|
||||
|
||||
[DataField]
|
||||
public float Max = float.PositiveInfinity;
|
||||
public override bool Condition(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.Source == null)
|
||||
return false;
|
||||
if (args.Source.Temperature < Min)
|
||||
return false;
|
||||
if (args.Source.Temperature > Max)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-solution-temperature",
|
||||
("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max),
|
||||
("min", Min));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffectConditions
|
||||
{
|
||||
public sealed partial class TotalDamage : ReagentEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 Max = FixedPoint2.MaxValue;
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 Min = FixedPoint2.Zero;
|
||||
|
||||
public override bool Condition(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent(args.SolutionEntity, out DamageableComponent? damage))
|
||||
{
|
||||
var total = damage.TotalDamage;
|
||||
if (total > Min && total < Max)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-total-damage",
|
||||
("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()),
|
||||
("min", Min.Float()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffectConditions
|
||||
{
|
||||
public sealed partial class Hunger : ReagentEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public float Max = float.PositiveInfinity;
|
||||
|
||||
[DataField]
|
||||
public float Min = 0;
|
||||
|
||||
public override bool Condition(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent(args.SolutionEntity, out HungerComponent? hunger))
|
||||
{
|
||||
var total = hunger.CurrentHunger;
|
||||
if (total > Min && total < Max)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-total-hunger",
|
||||
("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max),
|
||||
("min", Min));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class AddToSolutionReaction : ReagentEffect
|
||||
{
|
||||
[DataField("solution")]
|
||||
private string _solution = "reagents";
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.Reagent == null)
|
||||
return;
|
||||
|
||||
// TODO see if this is correct
|
||||
var solutionContainerSystem = args.EntityManager.System<SolutionContainerSystem>();
|
||||
if (!solutionContainerSystem.TryGetSolution(args.SolutionEntity, _solution, out var solutionContainer))
|
||||
return;
|
||||
|
||||
if (solutionContainerSystem.TryAddReagent(solutionContainer.Value, args.Reagent.ID, args.Quantity, out var accepted))
|
||||
args.Source?.RemoveReagent(args.Reagent.ID, accepted);
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
|
||||
Loc.GetString("reagent-effect-guidebook-add-to-solution-reaction", ("chance", Probability));
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReactionEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Basically smoke and foam reactions.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ChemCleanBloodstream : ReagentEffect
|
||||
{
|
||||
[DataField]
|
||||
public float CleanseRate = 3.0f;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-chem-clean-bloodstream", ("chance", Probability));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.Source == null || args.Reagent == null)
|
||||
return;
|
||||
|
||||
var cleanseRate = CleanseRate;
|
||||
|
||||
cleanseRate *= args.Scale;
|
||||
|
||||
var bloodstreamSys = args.EntityManager.System<BloodstreamSystem>();
|
||||
bloodstreamSys.FlushChemicals(args.SolutionEntity, args.Reagent.ID, cleanseRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Eye.Blinding;
|
||||
using Content.Shared.Eye.Blinding.Systems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Heal or apply eye damage
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ChemHealEyeDamage : ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// How much eye damage to add.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int Amount = -1;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-cure-eye-damage", ("chance", Probability), ("deltasign", MathF.Sign(Amount)));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.Scale != 1f) // huh?
|
||||
return;
|
||||
|
||||
args.EntityManager.EntitySysManager.GetEntitySystem<BlindableSystem>().AdjustEyeDamage(args.SolutionEntity, Amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using Content.Server.Electrocution;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
|
||||
public sealed partial class Electrocute : ReagentEffect
|
||||
{
|
||||
[DataField] public int ElectrocuteTime = 2;
|
||||
|
||||
[DataField] public int ElectrocuteDamageScale = 5;
|
||||
|
||||
/// <remarks>
|
||||
/// true - refresh electrocute time, false - accumulate electrocute time
|
||||
/// </remarks>
|
||||
[DataField] public bool Refresh = true;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-electrocute", ("chance", Probability), ("time", ElectrocuteTime));
|
||||
|
||||
public override bool ShouldLog => true;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
args.EntityManager.System<ElectrocutionSystem>().TryDoElectrocution(args.SolutionEntity, null,
|
||||
Math.Max((args.Quantity * ElectrocuteDamageScale).Int(), 1), TimeSpan.FromSeconds(ElectrocuteTime), Refresh, ignoreInsulation: true);
|
||||
|
||||
if (args.Reagent != null)
|
||||
args.Source?.RemoveReagent(args.Reagent.ID, args.Quantity);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ExtinguishReaction : ReagentEffect
|
||||
{
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-extinguish-reaction", ("chance", Probability));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out FlammableComponent? flammable)) return;
|
||||
|
||||
var flammableSystem = args.EntityManager.System<FlammableSystem>();
|
||||
flammableSystem.Extinguish(args.SolutionEntity, flammable);
|
||||
flammableSystem.AdjustFireStacks(args.SolutionEntity, -1.5f * (float) args.Quantity, flammable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Database;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class FlammableReaction : ReagentEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Multiplier = 0.05f;
|
||||
|
||||
public override bool ShouldLog => true;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-flammable-reaction", ("chance", Probability));
|
||||
|
||||
public override LogImpact LogImpact => LogImpact.Medium;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out FlammableComponent? flammable))
|
||||
return;
|
||||
|
||||
args.EntityManager.System<FlammableSystem>().AdjustFireStacks(args.SolutionEntity, args.Quantity.Float() * Multiplier, flammable);
|
||||
|
||||
if (args.Reagent != null)
|
||||
args.Source?.RemoveReagent(args.Reagent.ID, args.Quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
|
||||
public sealed partial class ModifyLungGas : ReagentEffect
|
||||
{
|
||||
[DataField("ratios", required: true)]
|
||||
private Dictionary<Gas, float> _ratios = default!;
|
||||
|
||||
// JUSTIFICATION: This is internal magic that players never directly interact with.
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> null;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent<LungComponent>(args.OrganEntity, out var lung))
|
||||
return;
|
||||
|
||||
foreach (var (gas, ratio) in _ratios)
|
||||
{
|
||||
var quantity = ratio * args.Quantity.Float() / Atmospherics.BreathMolesToReagentMultiplier;
|
||||
if (quantity < 0)
|
||||
quantity = Math.Max(quantity, -lung.Air[(int)gas]);
|
||||
lung.Air.AdjustMoles(gas, quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Default metabolism for stimulants and tranqs. Attempts to find a MovementSpeedModifier on the target,
|
||||
/// adding one if not there and to change the movespeed
|
||||
/// </summary>
|
||||
public sealed partial class MovespeedModifier : ReagentEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// How much the entities' walk speed is multiplied by.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float WalkSpeedModifier { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// How much the entities' run speed is multiplied by.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float SprintSpeedModifier { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// How long the modifier applies (in seconds) when metabolized.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float StatusLifetime = 2f;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-guidebook-movespeed-modifier",
|
||||
("chance", Probability),
|
||||
("walkspeed", WalkSpeedModifier),
|
||||
("time", StatusLifetime));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove reagent at set rate, changes the movespeed modifiers and adds a MovespeedModifierMetabolismComponent if not already there.
|
||||
/// </summary>
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
var status = args.EntityManager.EnsureComponent<MovespeedModifierMetabolismComponent>(args.SolutionEntity);
|
||||
|
||||
// Only refresh movement if we need to.
|
||||
var modified = !status.WalkSpeedModifier.Equals(WalkSpeedModifier) ||
|
||||
!status.SprintSpeedModifier.Equals(SprintSpeedModifier);
|
||||
|
||||
status.WalkSpeedModifier = WalkSpeedModifier;
|
||||
status.SprintSpeedModifier = SprintSpeedModifier;
|
||||
|
||||
// only going to scale application time
|
||||
var statusLifetime = StatusLifetime;
|
||||
statusLifetime *= args.Scale;
|
||||
|
||||
IncreaseTimer(status, statusLifetime);
|
||||
|
||||
if (modified)
|
||||
args.EntityManager.System<MovementSpeedModifierSystem>().RefreshMovementSpeedModifiers(args.SolutionEntity);
|
||||
|
||||
}
|
||||
public void IncreaseTimer(MovespeedModifierMetabolismComponent status, float time)
|
||||
{
|
||||
var gameTiming = IoCManager.Resolve<IGameTiming>();
|
||||
|
||||
var offsetTime = Math.Max(status.ModifierTimer.TotalSeconds, gameTiming.CurTime.TotalSeconds);
|
||||
|
||||
status.ModifierTimer = TimeSpan.FromSeconds(offsetTime + time);
|
||||
status.Dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
|
||||
public sealed partial class Oxygenate : ReagentEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Factor = 1f;
|
||||
|
||||
// JUSTIFICATION: This is internal magic that players never directly interact with.
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> null;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent<RespiratorComponent>(args.SolutionEntity, out var resp))
|
||||
{
|
||||
var respSys = args.EntityManager.System<RespiratorSystem>();
|
||||
respSys.UpdateSaturation(args.SolutionEntity, args.Quantity.Float() * Factor, resp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract partial class PlantAdjustAttribute : ReagentEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Amount { get; protected set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Localisation key for the name of the adjusted attribute. Used for guidebook descriptions.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public abstract string GuidebookAttributeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the attribute in question is a good thing. Used for guidebook descriptions to determine the color of the number.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public virtual bool GuidebookIsAttributePositive { get; protected set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the plant holder can metabolize the reagent or not. Checks if it has an alive plant by default.
|
||||
/// </summary>
|
||||
/// <param name="plantHolder">The entity holding the plant</param>
|
||||
/// <param name="plantHolderComponent">The plant holder component</param>
|
||||
/// <param name="entityManager">The entity manager</param>
|
||||
/// <param name="mustHaveAlivePlant">Whether to check if it has an alive plant or not</param>
|
||||
/// <returns></returns>
|
||||
public bool CanMetabolize(EntityUid plantHolder, [NotNullWhen(true)] out PlantHolderComponent? plantHolderComponent,
|
||||
IEntityManager entityManager,
|
||||
bool mustHaveAlivePlant = true)
|
||||
{
|
||||
plantHolderComponent = null;
|
||||
|
||||
if (!entityManager.TryGetComponent(plantHolder, out plantHolderComponent)
|
||||
|| mustHaveAlivePlant && (plantHolderComponent.Seed == null || plantHolderComponent.Dead))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
{
|
||||
string color;
|
||||
if (GuidebookIsAttributePositive ^ Amount < 0.0)
|
||||
{
|
||||
color = "green";
|
||||
}
|
||||
else
|
||||
{
|
||||
color = "red";
|
||||
}
|
||||
return Loc.GetString("reagent-effect-guidebook-plant-attribute", ("attribute", Loc.GetString(GuidebookAttributeName)), ("amount", Amount.ToString("0.00")), ("colorName", color), ("chance", Probability));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
public sealed partial class PlantAdjustHealth : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-health";
|
||||
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.SolutionEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
|
||||
plantHolderComp.Health += Amount;
|
||||
plantHolder.CheckHealth(args.SolutionEntity, plantHolderComp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
public sealed partial class PlantAdjustMutationLevel : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-level";
|
||||
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.SolutionEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
plantHolderComp.MutationLevel += Amount * plantHolderComp.MutationMod;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustMutationMod : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-mod";
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.SolutionEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
plantHolderComp.MutationMod += Amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustNutrition : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-nutrition";
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.SolutionEntity, out var plantHolderComp, args.EntityManager, mustHaveAlivePlant: false))
|
||||
return;
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
|
||||
plantHolder.AdjustNutrient(args.SolutionEntity, Amount, plantHolderComp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustPests : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-pests";
|
||||
public override bool GuidebookIsAttributePositive { get; protected set; } = false;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.SolutionEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
plantHolderComp.PestLevel += Amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustToxins : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-toxins";
|
||||
public override bool GuidebookIsAttributePositive { get; protected set; } = false;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.SolutionEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
plantHolderComp.Toxins += Amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustWater : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-water";
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.SolutionEntity, out var plantHolderComp, args.EntityManager, mustHaveAlivePlant: false))
|
||||
return;
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
|
||||
plantHolder.AdjustWater(args.SolutionEntity, Amount, plantHolderComp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustWeeds : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-weeds";
|
||||
public override bool GuidebookIsAttributePositive { get; protected set; } = false;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.SolutionEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
plantHolderComp.WeedLevel += Amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAffectGrowth : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-growth";
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.SolutionEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
|
||||
plantHolder.AffectGrowth(args.SolutionEntity, (int) Amount, plantHolderComp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class PlantCryoxadone : ReagentEffect
|
||||
{
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out PlantHolderComponent? plantHolderComp)
|
||||
|| plantHolderComp.Seed == null || plantHolderComp.Dead)
|
||||
return;
|
||||
|
||||
var deviation = 0;
|
||||
var seed = plantHolderComp.Seed;
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
if (plantHolderComp.Age > seed.Maturation)
|
||||
deviation = (int) Math.Max(seed.Maturation - 1, plantHolderComp.Age - random.Next(7, 10));
|
||||
else
|
||||
deviation = (int) (seed.Maturation / seed.GrowthStages);
|
||||
plantHolderComp.Age -= deviation;
|
||||
plantHolderComp.SkipAging++;
|
||||
plantHolderComp.ForceUpdate = true;
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-cryoxadone", ("chance", Probability));
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class PlantDiethylamine : ReagentEffect
|
||||
{
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out PlantHolderComponent? plantHolderComp)
|
||||
|| plantHolderComp.Seed == null || plantHolderComp.Dead ||
|
||||
plantHolderComp.Seed.Immutable)
|
||||
return;
|
||||
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
|
||||
if (random.Prob(0.1f))
|
||||
{
|
||||
plantHolder.EnsureUniqueSeed(args.SolutionEntity, plantHolderComp);
|
||||
plantHolderComp.Seed.Lifespan++;
|
||||
}
|
||||
|
||||
if (random.Prob(0.1f))
|
||||
{
|
||||
plantHolder.EnsureUniqueSeed(args.SolutionEntity, plantHolderComp);
|
||||
plantHolderComp.Seed.Endurance++;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-diethylamine", ("chance", Probability));
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class PlantPhalanximine : ReagentEffect
|
||||
{
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out PlantHolderComponent? plantHolderComp)
|
||||
|| plantHolderComp.Seed == null || plantHolderComp.Dead ||
|
||||
plantHolderComp.Seed.Immutable)
|
||||
return;
|
||||
|
||||
plantHolderComp.Seed.Viable = true;
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-phalanximine", ("chance", Probability));
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
|
||||
{
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class RobustHarvest : ReagentEffect
|
||||
{
|
||||
[DataField]
|
||||
public int PotencyLimit = 50;
|
||||
|
||||
[DataField]
|
||||
public int PotencyIncrease = 3;
|
||||
|
||||
[DataField]
|
||||
public int PotencySeedlessThreshold = 30;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out PlantHolderComponent? plantHolderComp)
|
||||
|| plantHolderComp.Seed == null || plantHolderComp.Dead ||
|
||||
plantHolderComp.Seed.Immutable)
|
||||
return;
|
||||
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
|
||||
if (plantHolderComp.Seed.Potency < PotencyLimit)
|
||||
{
|
||||
plantHolder.EnsureUniqueSeed(args.SolutionEntity, plantHolderComp);
|
||||
plantHolderComp.Seed.Potency = Math.Min(plantHolderComp.Seed.Potency + PotencyIncrease, PotencyLimit);
|
||||
|
||||
if (plantHolderComp.Seed.Potency > PotencySeedlessThreshold)
|
||||
{
|
||||
plantHolderComp.Seed.Seedless = true;
|
||||
}
|
||||
}
|
||||
else if (plantHolderComp.Seed.Yield > 1 && random.Prob(0.1f))
|
||||
{
|
||||
// Too much of a good thing reduces yield
|
||||
plantHolder.EnsureUniqueSeed(args.SolutionEntity, plantHolderComp);
|
||||
plantHolderComp.Seed.Yield--;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-robust-harvest", ("seedlesstreshold", PotencySeedlessThreshold), ("limit", PotencyLimit), ("increase", PotencyIncrease), ("chance", Probability));
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Default metabolism for drink reagents. Attempts to find a ThirstComponent on the target,
|
||||
/// and to update it's thirst values.
|
||||
/// </summary>
|
||||
public sealed partial class SatiateThirst : ReagentEffect
|
||||
{
|
||||
private const float DefaultHydrationFactor = 3.0f;
|
||||
|
||||
/// How much thirst is satiated each metabolism tick. Not currently tied to
|
||||
/// rate or anything.
|
||||
[DataField("factor")]
|
||||
public float HydrationFactor { get; set; } = DefaultHydrationFactor;
|
||||
|
||||
/// Satiate thirst if a ThirstComponent can be found
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
var uid = args.SolutionEntity;
|
||||
if (args.EntityManager.TryGetComponent(uid, out ThirstComponent? thirst))
|
||||
args.EntityManager.System<ThirstSystem>().ModifyThirst(uid, thirst, HydrationFactor);
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-satiate-thirst", ("chance", Probability), ("relative", HydrationFactor / DefaultHydrationFactor));
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.StatusEffect;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.StatusEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a generic status effect to the entity,
|
||||
/// not worrying about things like how to affect the time it lasts for
|
||||
/// or component fields or anything. Just adds a component to an entity
|
||||
/// for a given time. Easy.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Can be used for things like adding accents or something. I don't know. Go wild.
|
||||
/// </remarks>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class GenericStatusEffect : ReagentEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public string Key = default!;
|
||||
|
||||
[DataField]
|
||||
public string Component = String.Empty;
|
||||
|
||||
[DataField]
|
||||
public float Time = 2.0f;
|
||||
|
||||
/// <remarks>
|
||||
/// true - refresh status effect time, false - accumulate status effect time
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
public bool Refresh = true;
|
||||
|
||||
/// <summary>
|
||||
/// Should this effect add the status effect, remove time from it, or set its cooldown?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public StatusEffectMetabolismType Type = StatusEffectMetabolismType.Add;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
var statusSys = args.EntityManager.EntitySysManager.GetEntitySystem<StatusEffectsSystem>();
|
||||
|
||||
var time = Time;
|
||||
time *= args.Scale;
|
||||
|
||||
if (Type == StatusEffectMetabolismType.Add && Component != String.Empty)
|
||||
{
|
||||
statusSys.TryAddStatusEffect(args.SolutionEntity, Key, TimeSpan.FromSeconds(time), Refresh, Component);
|
||||
}
|
||||
else if (Type == StatusEffectMetabolismType.Remove)
|
||||
{
|
||||
statusSys.TryRemoveTime(args.SolutionEntity, Key, TimeSpan.FromSeconds(time));
|
||||
}
|
||||
else if (Type == StatusEffectMetabolismType.Set)
|
||||
{
|
||||
statusSys.TrySetTime(args.SolutionEntity, Key, TimeSpan.FromSeconds(time));
|
||||
}
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString(
|
||||
"reagent-effect-guidebook-status-effect",
|
||||
("chance", Probability),
|
||||
("type", Type),
|
||||
("time", Time),
|
||||
("key", $"reagent-effect-status-effect-{Key}"));
|
||||
}
|
||||
|
||||
public enum StatusEffectMetabolismType
|
||||
{
|
||||
Add,
|
||||
Remove,
|
||||
Set
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Jittering;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects.StatusEffects
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the jitter status effect to a mob.
|
||||
/// This doesn't use generic status effects because it needs to
|
||||
/// take in some parameters that JitterSystem needs.
|
||||
/// </summary>
|
||||
public sealed partial class Jitter : ReagentEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Amplitude = 10.0f;
|
||||
|
||||
[DataField]
|
||||
public float Frequency = 4.0f;
|
||||
|
||||
[DataField]
|
||||
public float Time = 2.0f;
|
||||
|
||||
/// <remarks>
|
||||
/// true - refresh jitter time, false - accumulate jitter time
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
public bool Refresh = true;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
var time = Time;
|
||||
time *= args.Scale;
|
||||
|
||||
args.EntityManager.EntitySysManager.GetEntitySystem<SharedJitteringSystem>()
|
||||
.DoJitter(args.SolutionEntity, TimeSpan.FromSeconds(time), Refresh, Amplitude, Frequency);
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
|
||||
Loc.GetString("reagent-effect-guidebook-jittering", ("chance", Probability));
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Content.Server.Nutrition.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class WashCreamPieReaction : ReagentEffect
|
||||
{
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-wash-cream-pie-reaction", ("chance", Probability));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out CreamPiedComponent? creamPied)) return;
|
||||
|
||||
args.EntityManager.System<CreamPieSystem>().SetCreamPied(args.SolutionEntity, creamPied, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.EffectConditions;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the target entity to be above or below a certain temperature.
|
||||
/// Used for things like cryoxadone and pyroxadone.
|
||||
/// </summary>
|
||||
public sealed partial class Temperature : EntityEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public float Min = 0;
|
||||
|
||||
[DataField]
|
||||
public float Max = float.PositiveInfinity;
|
||||
public override bool Condition(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent(args.TargetEntity, out TemperatureComponent? temp))
|
||||
{
|
||||
if (temp.CurrentTemperature > Min && temp.CurrentTemperature < Max)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-body-temperature",
|
||||
("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max),
|
||||
("min", Min));
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Tag;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffectConditions;
|
||||
namespace Content.Server.EntityEffects.EffectConditions;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class HasTag : ReagentEffectCondition
|
||||
public sealed partial class HasTag : EntityEffectCondition
|
||||
{
|
||||
[DataField(customTypeSerializer: typeof(PrototypeIdSerializer<TagPrototype>))]
|
||||
public string Tag = default!;
|
||||
@@ -15,9 +15,9 @@ public sealed partial class HasTag : ReagentEffectCondition
|
||||
[DataField]
|
||||
public bool Invert = false;
|
||||
|
||||
public override bool Condition(ReagentEffectArgs args)
|
||||
public override bool Condition(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent<TagComponent>(args.SolutionEntity, out var tag))
|
||||
if (args.EntityManager.TryGetComponent<TagComponent>(args.TargetEntity, out var tag))
|
||||
return args.EntityManager.System<TagSystem>().HasTag(tag, Tag) ^ Invert;
|
||||
|
||||
return false;
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Localizations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Roles.Jobs;
|
||||
using Content.Shared.Station;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Server.EntityEffects.EffectConditions;
|
||||
|
||||
public sealed partial class JobCondition : EntityEffectCondition
|
||||
{
|
||||
[DataField(required: true)] public List<ProtoId<JobPrototype>> Job;
|
||||
|
||||
public override bool Condition(EntityEffectBaseArgs args)
|
||||
{
|
||||
args.EntityManager.TryGetComponent<MindContainerComponent>(args.TargetEntity, out var mindContainer);
|
||||
if (mindContainer != null && mindContainer.Mind != null)
|
||||
{
|
||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
if (args.EntityManager.TryGetComponent<JobComponent>(mindContainer?.Mind, out var comp) && prototypeManager.TryIndex(comp.Prototype, out var prototype))
|
||||
{
|
||||
foreach (var jobId in Job)
|
||||
{
|
||||
if (prototype.ID == jobId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
var localizedNames = Job.Select(jobId => prototype.Index(jobId).LocalizedName).ToList();
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-job-condition", ("job", ContentLocalizationManager.FormatListToOr(localizedNames)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.EffectConditions;
|
||||
|
||||
public sealed partial class MobStateCondition : EntityEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public MobState Mobstate = MobState.Alive;
|
||||
|
||||
public override bool Condition(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent(args.TargetEntity, out MobStateComponent? mobState))
|
||||
{
|
||||
if (mobState.CurrentState == Mobstate)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-mob-state-condition", ("state", Mobstate));
|
||||
}
|
||||
}
|
||||
|
||||
53
Content.Server/EntityEffects/EffectConditions/OrganType.cs
Normal file
53
Content.Server/EntityEffects/EffectConditions/OrganType.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Shared.Body.Prototypes;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.EntityEffects.EffectConditions;
|
||||
|
||||
/// <summary>
|
||||
/// Requires that the metabolizing organ is or is not tagged with a certain MetabolizerType
|
||||
/// </summary>
|
||||
public sealed partial class OrganType : EntityEffectCondition
|
||||
{
|
||||
[DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<MetabolizerTypePrototype>))]
|
||||
public string Type = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Does this condition pass when the organ has the type, or when it doesn't have the type?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool ShouldHave = true;
|
||||
|
||||
public override bool Condition(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
if (reagentArgs.OrganEntity == null)
|
||||
return false;
|
||||
|
||||
return Condition(reagentArgs.OrganEntity.Value, reagentArgs.EntityManager);
|
||||
}
|
||||
|
||||
// TODO: Someone needs to figure out how to do this for non-reagent effects.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Condition(Entity<MetabolizerComponent?> metabolizer, IEntityManager entMan)
|
||||
{
|
||||
metabolizer.Comp ??= entMan.GetComponentOrNull<MetabolizerComponent>(metabolizer.Owner);
|
||||
if (metabolizer.Comp != null
|
||||
&& metabolizer.Comp.MetabolizerTypes != null
|
||||
&& metabolizer.Comp.MetabolizerTypes.Contains(Type))
|
||||
return ShouldHave;
|
||||
return !ShouldHave;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-organ-type",
|
||||
("name", prototype.Index<MetabolizerTypePrototype>(Type).LocalizedName),
|
||||
("shouldhave", ShouldHave));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.EffectConditions;
|
||||
|
||||
/// <summary>
|
||||
/// Used for implementing reagent effects that require a certain amount of reagent before it should be applied.
|
||||
/// For instance, overdoses.
|
||||
///
|
||||
/// This can also trigger on -other- reagents, not just the one metabolizing. By default, it uses the
|
||||
/// one being metabolized.
|
||||
/// </summary>
|
||||
public sealed partial class ReagentThreshold : EntityEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 Min = FixedPoint2.Zero;
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 Max = FixedPoint2.MaxValue;
|
||||
|
||||
// TODO use ReagentId
|
||||
[DataField]
|
||||
public string? Reagent;
|
||||
|
||||
public override bool Condition(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
var reagent = Reagent ?? reagentArgs.Reagent?.ID;
|
||||
if (reagent == null)
|
||||
return true; // No condition to apply.
|
||||
|
||||
var quant = FixedPoint2.Zero;
|
||||
if (reagentArgs.Source != null)
|
||||
quant = reagentArgs.Source.GetTotalPrototypeQuantity(reagent);
|
||||
|
||||
return quant >= Min && quant <= Max;
|
||||
}
|
||||
|
||||
// TODO: Someone needs to figure out how to do this for non-reagent effects.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
ReagentPrototype? reagentProto = null;
|
||||
if (Reagent is not null)
|
||||
prototype.TryIndex(Reagent, out reagentProto);
|
||||
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-reagent-threshold",
|
||||
("reagent", reagentProto?.LocalizedName ?? Loc.GetString("reagent-effect-condition-guidebook-this-reagent")),
|
||||
("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()),
|
||||
("min", Min.Float()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.EffectConditions;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the solution to be above or below a certain temperature.
|
||||
/// Used for things like explosives.
|
||||
/// </summary>
|
||||
public sealed partial class SolutionTemperature : EntityEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public float Min = 0.0f;
|
||||
|
||||
[DataField]
|
||||
public float Max = float.PositiveInfinity;
|
||||
public override bool Condition(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
if (reagentArgs.Source == null)
|
||||
return false;
|
||||
if (reagentArgs.Source.Temperature < Min)
|
||||
return false;
|
||||
if (reagentArgs.Source.Temperature > Max)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Someone needs to figure out how to do this for non-reagent effects.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-solution-temperature",
|
||||
("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max),
|
||||
("min", Min));
|
||||
}
|
||||
}
|
||||
34
Content.Server/EntityEffects/EffectConditions/TotalDamage.cs
Normal file
34
Content.Server/EntityEffects/EffectConditions/TotalDamage.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.EffectConditions;
|
||||
|
||||
public sealed partial class TotalDamage : EntityEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 Max = FixedPoint2.MaxValue;
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 Min = FixedPoint2.Zero;
|
||||
|
||||
public override bool Condition(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent(args.TargetEntity, out DamageableComponent? damage))
|
||||
{
|
||||
var total = damage.TotalDamage;
|
||||
if (total > Min && total < Max)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-total-damage",
|
||||
("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()),
|
||||
("min", Min.Float()));
|
||||
}
|
||||
}
|
||||
34
Content.Server/EntityEffects/EffectConditions/TotalHunger.cs
Normal file
34
Content.Server/EntityEffects/EffectConditions/TotalHunger.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.EffectConditions;
|
||||
|
||||
public sealed partial class Hunger : EntityEffectCondition
|
||||
{
|
||||
[DataField]
|
||||
public float Max = float.PositiveInfinity;
|
||||
|
||||
[DataField]
|
||||
public float Min = 0;
|
||||
|
||||
public override bool Condition(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent(args.TargetEntity, out HungerComponent? hunger))
|
||||
{
|
||||
var total = hunger.CurrentHunger;
|
||||
if (total > Min && total < Max)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GuidebookExplanation(IPrototypeManager prototype)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-condition-guidebook-total-hunger",
|
||||
("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max),
|
||||
("min", Min));
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
using Content.Server.Xenoarchaeology.XenoArtifacts;
|
||||
using Content.Server.Xenoarchaeology.XenoArtifacts;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.EntityEffects;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class ActivateArtifact : ReagentEffect
|
||||
public sealed partial class ActivateArtifact : EntityEffect
|
||||
{
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var artifact = args.EntityManager.EntitySysManager.GetEntitySystem<ArtifactSystem>();
|
||||
artifact.TryActivateArtifact(args.SolutionEntity);
|
||||
artifact.TryActivateArtifact(args.TargetEntity);
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
|
||||
@@ -0,0 +1,38 @@
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class AddToSolutionReaction : EntityEffect
|
||||
{
|
||||
[DataField("solution")]
|
||||
private string _solution = "reagents";
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args is EntityEffectReagentArgs reagentArgs) {
|
||||
if (reagentArgs.Reagent == null)
|
||||
return;
|
||||
|
||||
// TODO see if this is correct
|
||||
var solutionContainerSystem = reagentArgs.EntityManager.System<SolutionContainerSystem>();
|
||||
if (!solutionContainerSystem.TryGetSolution(reagentArgs.TargetEntity, _solution, out var solutionContainer))
|
||||
return;
|
||||
|
||||
if (solutionContainerSystem.TryAddReagent(solutionContainer.Value, reagentArgs.Reagent.ID, reagentArgs.Quantity, out var accepted))
|
||||
reagentArgs.Source?.RemoveReagent(reagentArgs.Reagent.ID, accepted);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Someone needs to figure out how to do this for non-reagent effects.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
|
||||
Loc.GetString("reagent-effect-guidebook-add-to-solution-reaction", ("chance", Probability));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class AdjustAlert : ReagentEffect
|
||||
public sealed partial class AdjustAlert : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The specific Alert that will be adjusted
|
||||
@@ -34,15 +34,15 @@ public sealed partial class AdjustAlert : ReagentEffect
|
||||
//JUSTIFICATION: This just changes some visuals, doesn't need to be documented.
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => null;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var alertSys = args.EntityManager.EntitySysManager.GetEntitySystem<AlertsSystem>();
|
||||
if (!args.EntityManager.HasComponent<AlertsComponent>(args.SolutionEntity))
|
||||
if (!args.EntityManager.HasComponent<AlertsComponent>(args.TargetEntity))
|
||||
return;
|
||||
|
||||
if (Clear && Time <= 0)
|
||||
{
|
||||
alertSys.ClearAlert(args.SolutionEntity, AlertType);
|
||||
alertSys.ClearAlert(args.TargetEntity, AlertType);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -52,7 +52,7 @@ public sealed partial class AdjustAlert : ReagentEffect
|
||||
if ((ShowCooldown || Clear) && Time > 0)
|
||||
cooldown = (timing.CurTime, timing.CurTime + TimeSpan.FromSeconds(Time));
|
||||
|
||||
alertSys.ShowAlert(args.SolutionEntity, AlertType, cooldown: cooldown, autoRemove: Clear, showCooldown: ShowCooldown);
|
||||
alertSys.ShowAlert(args.TargetEntity, AlertType, cooldown: cooldown, autoRemove: Clear, showCooldown: ShowCooldown);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
using Content.Shared.Body.Prototypes;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.FixedPoint;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class AdjustReagent : ReagentEffect
|
||||
public sealed partial class AdjustReagent : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The reagent ID to remove. Only one of this and <see cref="Group"/> should be active.
|
||||
@@ -27,36 +28,43 @@ namespace Content.Server.Chemistry.ReagentEffects
|
||||
[DataField(required: true)]
|
||||
public FixedPoint2 Amount = default!;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.Source == null)
|
||||
return;
|
||||
|
||||
var amount = Amount;
|
||||
amount *= args.Scale;
|
||||
|
||||
if (Reagent != null)
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
if (amount < 0 && args.Source.ContainsPrototype(Reagent))
|
||||
args.Source.RemoveReagent(Reagent, -amount);
|
||||
if (amount > 0)
|
||||
args.Source.AddReagent(Reagent, amount);
|
||||
}
|
||||
else if (Group != null)
|
||||
{
|
||||
var prototypeMan = IoCManager.Resolve<IPrototypeManager>();
|
||||
foreach (var quant in args.Source.Contents.ToArray())
|
||||
if (reagentArgs.Source == null)
|
||||
return;
|
||||
|
||||
var amount = Amount;
|
||||
amount *= reagentArgs.Scale;
|
||||
|
||||
if (Reagent != null)
|
||||
{
|
||||
var proto = prototypeMan.Index<ReagentPrototype>(quant.Reagent.Prototype);
|
||||
if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group))
|
||||
if (amount < 0 && reagentArgs.Source.ContainsPrototype(Reagent))
|
||||
reagentArgs.Source.RemoveReagent(Reagent, -amount);
|
||||
if (amount > 0)
|
||||
reagentArgs.Source.AddReagent(Reagent, amount);
|
||||
}
|
||||
else if (Group != null)
|
||||
{
|
||||
var prototypeMan = IoCManager.Resolve<IPrototypeManager>();
|
||||
foreach (var quant in reagentArgs.Source.Contents.ToArray())
|
||||
{
|
||||
if (amount < 0)
|
||||
args.Source.RemoveReagent(quant.Reagent, amount);
|
||||
if (amount > 0)
|
||||
args.Source.AddReagent(quant.Reagent, amount);
|
||||
var proto = prototypeMan.Index<ReagentPrototype>(quant.Reagent.Prototype);
|
||||
if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group))
|
||||
{
|
||||
if (amount < 0)
|
||||
reagentArgs.Source.RemoveReagent(quant.Reagent, amount);
|
||||
if (amount > 0)
|
||||
reagentArgs.Source.AddReagent(quant.Reagent, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Someone needs to figure out how to do this for non-reagent effects.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
@@ -1,11 +1,11 @@
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Server.Temperature.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
public sealed partial class AdjustTemperature : ReagentEffect
|
||||
public sealed partial class AdjustTemperature : EntityEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Amount;
|
||||
@@ -16,16 +16,19 @@ namespace Content.Server.Chemistry.ReagentEffects
|
||||
("deltasign", MathF.Sign(Amount)),
|
||||
("amount", MathF.Abs(Amount)));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent(args.SolutionEntity, out TemperatureComponent? temp))
|
||||
if (args.EntityManager.TryGetComponent(args.TargetEntity, out TemperatureComponent? temp))
|
||||
{
|
||||
var sys = args.EntityManager.EntitySysManager.GetEntitySystem<TemperatureSystem>();
|
||||
var amount = Amount;
|
||||
|
||||
amount *= args.Scale;
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
amount *= reagentArgs.Scale.Float();
|
||||
}
|
||||
|
||||
sys.ChangeHeat(args.SolutionEntity, amount, true, temp);
|
||||
sys.ChangeHeat(args.TargetEntity, amount, true, temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Content.Server/EntityEffects/Effects/AreaReactionEffect.cs
Normal file
91
Content.Server/EntityEffects/Effects/AreaReactionEffect.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using Content.Server.Fluids.EntitySystems;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Coordinates.Helpers;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Maps;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
/// <summary>
|
||||
/// Basically smoke and foam reactions.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class AreaReactionEffect : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// How many seconds will the effect stay, counting after fully spreading.
|
||||
/// </summary>
|
||||
[DataField("duration")] private float _duration = 10;
|
||||
|
||||
/// <summary>
|
||||
/// How many units of reaction for 1 smoke entity.
|
||||
/// </summary>
|
||||
[DataField] public FixedPoint2 OverflowThreshold = FixedPoint2.New(2.5);
|
||||
|
||||
/// <summary>
|
||||
/// The entity prototype that will be spawned as the effect.
|
||||
/// </summary>
|
||||
[DataField("prototypeId", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
private string _prototypeId = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Sound that will get played when this reaction effect occurs.
|
||||
/// </summary>
|
||||
[DataField("sound", required: true)] private SoundSpecifier _sound = default!;
|
||||
|
||||
public override bool ShouldLog => true;
|
||||
|
||||
protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-area-reaction",
|
||||
("duration", _duration)
|
||||
);
|
||||
|
||||
public override LogImpact LogImpact => LogImpact.High;
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
if (reagentArgs.Source == null)
|
||||
return;
|
||||
|
||||
var spreadAmount = (int) Math.Max(0, Math.Ceiling((reagentArgs.Quantity / OverflowThreshold).Float()));
|
||||
var splitSolution = reagentArgs.Source.SplitSolution(reagentArgs.Source.Volume);
|
||||
var transform = reagentArgs.EntityManager.GetComponent<TransformComponent>(reagentArgs.TargetEntity);
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
var mapSys = reagentArgs.EntityManager.System<MapSystem>();
|
||||
var sys = reagentArgs.EntityManager.System<TransformSystem>();
|
||||
var mapCoords = sys.GetMapCoordinates(reagentArgs.TargetEntity, xform: transform);
|
||||
|
||||
if (!mapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid) ||
|
||||
!mapSys.TryGetTileRef(gridUid, grid, transform.Coordinates, out var tileRef) ||
|
||||
tileRef.Tile.IsSpace())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var coords = mapSys.MapToGrid(gridUid, mapCoords);
|
||||
var ent = reagentArgs.EntityManager.SpawnEntity(_prototypeId, coords.SnapToGrid());
|
||||
|
||||
var smoke = reagentArgs.EntityManager.System<SmokeSystem>();
|
||||
smoke.StartSmoke(ent, splitSolution, _duration, spreadAmount);
|
||||
|
||||
var audio = reagentArgs.EntityManager.System<SharedAudioSystem>();
|
||||
audio.PlayPvs(_sound, reagentArgs.TargetEntity, AudioHelpers.WithVariation(0.125f));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Someone needs to figure out how to do this for non-reagent effects.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
using Content.Server.Zombies;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Configuration;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Zombies;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class CauseZombieInfection : ReagentEffect
|
||||
public sealed partial class CauseZombieInfection : EntityEffect
|
||||
{
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-cause-zombie-infection", ("chance", Probability));
|
||||
|
||||
// Adds the Zombie Infection Components
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var entityManager = args.EntityManager;
|
||||
entityManager.EnsureComponent<ZombifyOnDeathComponent>(args.SolutionEntity);
|
||||
entityManager.EnsureComponent<PendingZombieComponent>(args.SolutionEntity);
|
||||
entityManager.EnsureComponent<ZombifyOnDeathComponent>(args.TargetEntity);
|
||||
entityManager.EnsureComponent<PendingZombieComponent>(args.TargetEntity);
|
||||
}
|
||||
}
|
||||
|
||||
40
Content.Server/EntityEffects/Effects/ChemCleanBloodstream.cs
Normal file
40
Content.Server/EntityEffects/Effects/ChemCleanBloodstream.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
/// <summary>
|
||||
/// Basically smoke and foam reactions.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ChemCleanBloodstream : EntityEffect
|
||||
{
|
||||
[DataField]
|
||||
public float CleanseRate = 3.0f;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-chem-clean-bloodstream", ("chance", Probability));
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
|
||||
var cleanseRate = CleanseRate;
|
||||
|
||||
var bloodstreamSys = args.EntityManager.System<BloodstreamSystem>();
|
||||
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
if (reagentArgs.Source == null || reagentArgs.Reagent == null)
|
||||
return;
|
||||
|
||||
cleanseRate *= reagentArgs.Scale.Float();
|
||||
bloodstreamSys.FlushChemicals(args.TargetEntity, reagentArgs.Reagent.ID, cleanseRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
bloodstreamSys.FlushChemicals(args.TargetEntity, "", cleanseRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Content.Server/EntityEffects/Effects/ChemHealEyeDamage.cs
Normal file
31
Content.Server/EntityEffects/Effects/ChemHealEyeDamage.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Eye.Blinding.Systems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
/// <summary>
|
||||
/// Heal or apply eye damage
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ChemHealEyeDamage : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// How much eye damage to add.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int Amount = -1;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-cure-eye-damage", ("chance", Probability), ("deltasign", MathF.Sign(Amount)));
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
if (reagentArgs.Scale != 1f) // huh?
|
||||
return;
|
||||
|
||||
args.EntityManager.EntitySysManager.GetEntitySystem<BlindableSystem>().AdjustEyeDamage(args.TargetEntity, Amount);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
using Content.Server.Medical;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
/// <summary>
|
||||
/// Forces you to vomit.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ChemVomit : ReagentEffect
|
||||
public sealed partial class ChemVomit : EntityEffect
|
||||
{
|
||||
/// How many units of thirst to add each time we vomit
|
||||
[DataField]
|
||||
@@ -21,14 +21,15 @@ namespace Content.Server.Chemistry.ReagentEffects
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-chem-vomit", ("chance", Probability));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.Scale != 1f)
|
||||
return;
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
if (reagentArgs.Scale != 1f)
|
||||
return;
|
||||
|
||||
var vomitSys = args.EntityManager.EntitySysManager.GetEntitySystem<VomitSystem>();
|
||||
|
||||
vomitSys.Vomit(args.SolutionEntity, ThirstAmount, HungerAmount);
|
||||
vomitSys.Vomit(args.TargetEntity, ThirstAmount, HungerAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Chemistry.ReactionEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
[DataDefinition]
|
||||
public sealed partial class CreateEntityReactionEffect : ReagentEffect
|
||||
public sealed partial class CreateEntityReactionEffect : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// What entity to create.
|
||||
@@ -26,15 +25,17 @@ public sealed partial class CreateEntityReactionEffect : ReagentEffect
|
||||
("entname", IoCManager.Resolve<IPrototypeManager>().Index<EntityPrototype>(Entity).Name),
|
||||
("amount", Number));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var transform = args.EntityManager.GetComponent<TransformComponent>(args.SolutionEntity);
|
||||
var transform = args.EntityManager.GetComponent<TransformComponent>(args.TargetEntity);
|
||||
var transformSystem = args.EntityManager.System<SharedTransformSystem>();
|
||||
var quantity = Number * args.Quantity.Int();
|
||||
var quantity = (int)Number;
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
quantity *= reagentArgs.Quantity.Int();
|
||||
|
||||
for (var i = 0; i < quantity; i++)
|
||||
{
|
||||
var uid = args.EntityManager.SpawnEntity(Entity, transformSystem.GetMapCoordinates(args.SolutionEntity, xform: transform));
|
||||
var uid = args.EntityManager.SpawnEntity(Entity, transformSystem.GetMapCoordinates(args.TargetEntity, xform: transform));
|
||||
transformSystem.AttachToGridOrMap(uid);
|
||||
|
||||
// TODO figure out how to properly spawn inside of containers
|
||||
@@ -1,12 +1,12 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class CreateGas : ReagentEffect
|
||||
public sealed partial class CreateGas : EntityEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public Gas Gas = default!;
|
||||
@@ -31,15 +31,22 @@ public sealed partial class CreateGas : ReagentEffect
|
||||
|
||||
public override LogImpact LogImpact => LogImpact.High;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var atmosSys = args.EntityManager.EntitySysManager.GetEntitySystem<AtmosphereSystem>();
|
||||
|
||||
var tileMix = atmosSys.GetContainingMixture(args.SolutionEntity, false, true);
|
||||
var tileMix = atmosSys.GetContainingMixture(args.TargetEntity, false, true);
|
||||
|
||||
if (tileMix != null)
|
||||
{
|
||||
tileMix.AdjustMoles(Gas, args.Quantity.Float() * Multiplier);
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
tileMix.AdjustMoles(Gas, reagentArgs.Quantity.Float() * Multiplier);
|
||||
}
|
||||
else
|
||||
{
|
||||
tileMix.AdjustMoles(Gas, Multiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
using Content.Server.Zombies;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Configuration;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Zombies;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class CureZombieInfection : ReagentEffect
|
||||
public sealed partial class CureZombieInfection : EntityEffect
|
||||
{
|
||||
[DataField]
|
||||
public bool Innoculate;
|
||||
@@ -20,18 +19,18 @@ public sealed partial class CureZombieInfection : ReagentEffect
|
||||
}
|
||||
|
||||
// Removes the Zombie Infection Components
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var entityManager = args.EntityManager;
|
||||
if (entityManager.HasComponent<IncurableZombieComponent>(args.SolutionEntity))
|
||||
if (entityManager.HasComponent<IncurableZombieComponent>(args.TargetEntity))
|
||||
return;
|
||||
|
||||
entityManager.RemoveComponent<ZombifyOnDeathComponent>(args.SolutionEntity);
|
||||
entityManager.RemoveComponent<PendingZombieComponent>(args.SolutionEntity);
|
||||
entityManager.RemoveComponent<ZombifyOnDeathComponent>(args.TargetEntity);
|
||||
entityManager.RemoveComponent<PendingZombieComponent>(args.TargetEntity);
|
||||
|
||||
if (Innoculate)
|
||||
{
|
||||
entityManager.EnsureComponent<ZombieImmuneComponent>(args.SolutionEntity);
|
||||
entityManager.EnsureComponent<ZombieImmuneComponent>(args.TargetEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Drunk;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class Drunk : ReagentEffect
|
||||
public sealed partial class Drunk : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// BoozePower is how long each metabolism cycle will make the drunk effect last for.
|
||||
@@ -21,13 +21,15 @@ public sealed partial class Drunk : ReagentEffect
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-drunk", ("chance", Probability));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var boozePower = BoozePower;
|
||||
|
||||
boozePower *= args.Scale;
|
||||
|
||||
if (args is EntityEffectReagentArgs reagentArgs) {
|
||||
boozePower *= reagentArgs.Scale.Float();
|
||||
}
|
||||
|
||||
var drunkSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedDrunkSystem>();
|
||||
drunkSys.TryApplyDrunkenness(args.SolutionEntity, boozePower, SlurSpeech);
|
||||
drunkSys.TryApplyDrunkenness(args.TargetEntity, boozePower, SlurSpeech);
|
||||
}
|
||||
}
|
||||
38
Content.Server/EntityEffects/Effects/Electrocute.cs
Normal file
38
Content.Server/EntityEffects/Effects/Electrocute.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Content.Server.Electrocution;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class Electrocute : EntityEffect
|
||||
{
|
||||
[DataField] public int ElectrocuteTime = 2;
|
||||
|
||||
[DataField] public int ElectrocuteDamageScale = 5;
|
||||
|
||||
/// <remarks>
|
||||
/// true - refresh electrocute time, false - accumulate electrocute time
|
||||
/// </remarks>
|
||||
[DataField] public bool Refresh = true;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-electrocute", ("chance", Probability), ("time", ElectrocuteTime));
|
||||
|
||||
public override bool ShouldLog => true;
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
reagentArgs.EntityManager.System<ElectrocutionSystem>().TryDoElectrocution(reagentArgs.TargetEntity, null,
|
||||
Math.Max((reagentArgs.Quantity * ElectrocuteDamageScale).Int(), 1), TimeSpan.FromSeconds(ElectrocuteTime), Refresh, ignoreInsulation: true);
|
||||
|
||||
if (reagentArgs.Reagent != null)
|
||||
reagentArgs.Source?.RemoveReagent(reagentArgs.Reagent.ID, reagentArgs.Quantity);
|
||||
} else
|
||||
{
|
||||
args.EntityManager.System<ElectrocutionSystem>().TryDoElectrocution(args.TargetEntity, null,
|
||||
Math.Max(ElectrocuteDamageScale, 1), TimeSpan.FromSeconds(ElectrocuteTime), Refresh, ignoreInsulation: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to force someone to emote (scream, laugh, etc). Still respects whitelists/blacklists and other limits of the specified emote unless forced.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class Emote : ReagentEffect
|
||||
public sealed partial class Emote : EntityEffect
|
||||
{
|
||||
[DataField("emote", customTypeSerializer: typeof(PrototypeIdSerializer<EmotePrototype>))]
|
||||
public string? EmoteId;
|
||||
@@ -26,16 +26,16 @@ public sealed partial class Emote : ReagentEffect
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> null;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (EmoteId == null)
|
||||
return;
|
||||
|
||||
var chatSys = args.EntityManager.System<ChatSystem>();
|
||||
if (ShowInChat)
|
||||
chatSys.TryEmoteWithChat(args.SolutionEntity, EmoteId, ChatTransmitRange.GhostRangeLimit, forceEmote: Force);
|
||||
chatSys.TryEmoteWithChat(args.TargetEntity, EmoteId, ChatTransmitRange.GhostRangeLimit, forceEmote: Force);
|
||||
else
|
||||
chatSys.TryEmoteWithoutChat(args.SolutionEntity, EmoteId);
|
||||
chatSys.TryEmoteWithoutChat(args.TargetEntity, EmoteId);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
using Content.Server.Emp;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReactionEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
|
||||
[DataDefinition]
|
||||
public sealed partial class EmpReactionEffect : ReagentEffect
|
||||
public sealed partial class EmpReactionEffect : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// Impulse range per unit of reagent
|
||||
/// Impulse range per unit of quantity
|
||||
/// </summary>
|
||||
[DataField("rangePerUnit")]
|
||||
public float EmpRangePerUnit = 0.5f;
|
||||
@@ -36,14 +37,20 @@ public sealed partial class EmpReactionEffect : ReagentEffect
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-emp-reaction-effect", ("chance", Probability));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var tSys = args.EntityManager.System<TransformSystem>();
|
||||
var transform = args.EntityManager.GetComponent<TransformComponent>(args.SolutionEntity);
|
||||
var range = MathF.Min((float) (args.Quantity*EmpRangePerUnit), EmpMaxRange);
|
||||
var transform = args.EntityManager.GetComponent<TransformComponent>(args.TargetEntity);
|
||||
|
||||
var range = EmpRangePerUnit;
|
||||
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
range = MathF.Min((float) (reagentArgs.Quantity * EmpRangePerUnit), EmpMaxRange);
|
||||
}
|
||||
|
||||
args.EntityManager.System<EmpSystem>()
|
||||
.EmpPulse(tSys.GetMapCoordinates(args.SolutionEntity, xform: transform),
|
||||
.EmpPulse(tSys.GetMapCoordinates(args.TargetEntity, xform: transform),
|
||||
range,
|
||||
EnergyConsumption,
|
||||
DisableDuration);
|
||||
@@ -0,0 +1,77 @@
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Explosion;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
[DataDefinition]
|
||||
public sealed partial class ExplosionReactionEffect : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of explosion. Determines damage types and tile break chance scaling.
|
||||
/// </summary>
|
||||
[DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<ExplosionPrototype>))]
|
||||
[JsonIgnore]
|
||||
public string ExplosionType = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The max intensity the explosion can have at a given tile. Places an upper limit of damage and tile break
|
||||
/// chance.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[JsonIgnore]
|
||||
public float MaxIntensity = 5;
|
||||
|
||||
/// <summary>
|
||||
/// How quickly intensity drops off as you move away from the epicenter
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[JsonIgnore]
|
||||
public float IntensitySlope = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum total intensity that this chemical reaction can achieve. Basically here to prevent people
|
||||
/// from creating a nuke by collecting enough potassium and water.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A slope of 1 and MaxTotalIntensity of 100 corresponds to a radius of around 4.5 tiles.
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
[JsonIgnore]
|
||||
public float MaxTotalIntensity = 100;
|
||||
|
||||
/// <summary>
|
||||
/// The intensity of the explosion per unit reaction.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[JsonIgnore]
|
||||
public float IntensityPerUnit = 1;
|
||||
|
||||
public override bool ShouldLog => true;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-explosion-reaction-effect", ("chance", Probability));
|
||||
public override LogImpact LogImpact => LogImpact.High;
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var intensity = IntensityPerUnit;
|
||||
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
intensity = MathF.Min((float) reagentArgs.Quantity * IntensityPerUnit, MaxTotalIntensity);
|
||||
}
|
||||
|
||||
args.EntityManager.System<ExplosionSystem>()
|
||||
.QueueExplosion(
|
||||
args.TargetEntity,
|
||||
ExplosionType,
|
||||
intensity,
|
||||
IntensitySlope,
|
||||
MaxIntensity);
|
||||
}
|
||||
}
|
||||
36
Content.Server/EntityEffects/Effects/ExtinguishReaction.cs
Normal file
36
Content.Server/EntityEffects/Effects/ExtinguishReaction.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ExtinguishReaction : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// Amount of firestacks reduced.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float FireStacksAdjustment = -1.5f;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-extinguish-reaction", ("chance", Probability));
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.TargetEntity, out FlammableComponent? flammable)) return;
|
||||
|
||||
var flammableSystem = args.EntityManager.System<FlammableSystem>();
|
||||
flammableSystem.Extinguish(args.TargetEntity, flammable);
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
flammableSystem.AdjustFireStacks(reagentArgs.TargetEntity, FireStacksAdjustment * (float) reagentArgs.Quantity, flammable);
|
||||
} else
|
||||
{
|
||||
flammableSystem.AdjustFireStacks(args.TargetEntity, FireStacksAdjustment, flammable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
Content.Server/EntityEffects/Effects/FlammableReaction.cs
Normal file
45
Content.Server/EntityEffects/Effects/FlammableReaction.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class FlammableReaction : EntityEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Multiplier = 0.05f;
|
||||
|
||||
[DataField]
|
||||
public float MultiplierOnExisting = 1f;
|
||||
|
||||
public override bool ShouldLog => true;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-flammable-reaction", ("chance", Probability));
|
||||
|
||||
public override LogImpact LogImpact => LogImpact.Medium;
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.TargetEntity, out FlammableComponent? flammable))
|
||||
return;
|
||||
|
||||
var multiplier = flammable.FireStacks == 0f ? Multiplier : MultiplierOnExisting;
|
||||
var quantity = 1f;
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
quantity = reagentArgs.Quantity.Float();
|
||||
reagentArgs.EntityManager.System<FlammableSystem>().AdjustFireStacks(args.TargetEntity, quantity * multiplier, flammable);
|
||||
if (reagentArgs.Reagent != null)
|
||||
reagentArgs.Source?.RemoveReagent(reagentArgs.Reagent.ID, reagentArgs.Quantity);
|
||||
} else
|
||||
{
|
||||
args.EntityManager.System<FlammableSystem>().AdjustFireStacks(args.TargetEntity, multiplier, flammable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Localizations;
|
||||
using JetBrains.Annotations;
|
||||
@@ -8,16 +8,16 @@ using Robust.Shared.Prototypes;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
/// <summary>
|
||||
/// Default metabolism for medicine reagents.
|
||||
/// Default metabolism used for medicine reagents.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class HealthChange : ReagentEffect
|
||||
public sealed partial class HealthChange : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// Damage to apply every metabolism cycle. Damage Ignores resistances.
|
||||
/// Damage to apply every cycle. Damage Ignores resistances.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
[JsonPropertyName("damage")]
|
||||
@@ -26,6 +26,7 @@ namespace Content.Server.Chemistry.ReagentEffects
|
||||
/// <summary>
|
||||
/// Should this effect scale the damage by the amount of chemical in the solution?
|
||||
/// Useful for touch reactions, like styptic powder or acid.
|
||||
/// Only usable if the EntityEffectBaseArgs is an EntityEffectReagentArgs.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[JsonPropertyName("scaleByQuantity")]
|
||||
@@ -110,13 +111,17 @@ namespace Content.Server.Chemistry.ReagentEffects
|
||||
("healsordeals", healsordeals));
|
||||
}
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var scale = ScaleByQuantity ? args.Quantity : FixedPoint2.New(1);
|
||||
scale *= args.Scale;
|
||||
var scale = FixedPoint2.New(1);
|
||||
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
scale = ScaleByQuantity ? reagentArgs.Quantity * reagentArgs.Scale : reagentArgs.Scale;
|
||||
}
|
||||
|
||||
args.EntityManager.System<DamageableSystem>().TryChangeDamage(
|
||||
args.SolutionEntity,
|
||||
args.TargetEntity,
|
||||
Damage * scale,
|
||||
IgnoreResistances,
|
||||
interruptsDoAfters: false);
|
||||
@@ -1,14 +1,14 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
/// <summary>
|
||||
/// Ignites a mob.
|
||||
/// </summary>
|
||||
public sealed partial class Ignite : ReagentEffect
|
||||
public sealed partial class Ignite : EntityEffect
|
||||
{
|
||||
public override bool ShouldLog => true;
|
||||
|
||||
@@ -17,9 +17,15 @@ public sealed partial class Ignite : ReagentEffect
|
||||
|
||||
public override LogImpact LogImpact => LogImpact.Medium;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var flamSys = args.EntityManager.System<FlammableSystem>();
|
||||
flamSys.Ignite(args.SolutionEntity, args.OrganEntity ?? args.SolutionEntity);
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
flamSys.Ignite(reagentArgs.TargetEntity, reagentArgs.OrganEntity ?? reagentArgs.TargetEntity);
|
||||
} else
|
||||
{
|
||||
flamSys.Ignite(args.TargetEntity, args.TargetEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
using Content.Server.Ghost.Roles.Components;
|
||||
using Content.Server.Speech.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class MakeSentient : ReagentEffect
|
||||
public sealed partial class MakeSentient : EntityEffect
|
||||
{
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-make-sentient", ("chance", Probability));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var entityManager = args.EntityManager;
|
||||
var uid = args.SolutionEntity;
|
||||
var uid = args.TargetEntity;
|
||||
|
||||
// Let affected entities speak normally to make this effect different from, say, the "random sentience" event
|
||||
// This also works on entities that already have a mind
|
||||
@@ -1,11 +1,11 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class ModifyBleedAmount : ReagentEffect
|
||||
public sealed partial class ModifyBleedAmount : EntityEffect
|
||||
{
|
||||
[DataField]
|
||||
public bool Scaled = false;
|
||||
@@ -17,15 +17,19 @@ public sealed partial class ModifyBleedAmount : ReagentEffect
|
||||
=> Loc.GetString("reagent-effect-guidebook-modify-bleed-amount", ("chance", Probability),
|
||||
("deltasign", MathF.Sign(Amount)));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent<BloodstreamComponent>(args.SolutionEntity, out var blood))
|
||||
if (args.EntityManager.TryGetComponent<BloodstreamComponent>(args.TargetEntity, out var blood))
|
||||
{
|
||||
var sys = args.EntityManager.System<BloodstreamSystem>();
|
||||
var amt = Scaled ? Amount * args.Quantity.Float() : Amount;
|
||||
amt *= args.Scale;
|
||||
var amt = Amount;
|
||||
if (args is EntityEffectReagentArgs reagentArgs) {
|
||||
if (Scaled)
|
||||
amt *= reagentArgs.Quantity.Float();
|
||||
amt *= reagentArgs.Scale.Float();
|
||||
}
|
||||
|
||||
sys.TryModifyBleedAmount(args.SolutionEntity, amt, blood);
|
||||
sys.TryModifyBleedAmount(args.TargetEntity, amt, blood);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class ModifyBloodLevel : ReagentEffect
|
||||
public sealed partial class ModifyBloodLevel : EntityEffect
|
||||
{
|
||||
[DataField]
|
||||
public bool Scaled = false;
|
||||
@@ -18,15 +18,20 @@ public sealed partial class ModifyBloodLevel : ReagentEffect
|
||||
=> Loc.GetString("reagent-effect-guidebook-modify-blood-level", ("chance", Probability),
|
||||
("deltasign", MathF.Sign(Amount.Float())));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent<BloodstreamComponent>(args.SolutionEntity, out var blood))
|
||||
if (args.EntityManager.TryGetComponent<BloodstreamComponent>(args.TargetEntity, out var blood))
|
||||
{
|
||||
var sys = args.EntityManager.System<BloodstreamSystem>();
|
||||
var amt = Scaled ? Amount * args.Quantity : Amount;
|
||||
amt *= args.Scale;
|
||||
var amt = Amount;
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
if (Scaled)
|
||||
amt *= reagentArgs.Quantity;
|
||||
amt *= reagentArgs.Scale;
|
||||
}
|
||||
|
||||
sys.TryModifyBloodLevel(args.SolutionEntity, amt, blood);
|
||||
sys.TryModifyBloodLevel(args.TargetEntity, amt, blood);
|
||||
}
|
||||
}
|
||||
}
|
||||
49
Content.Server/EntityEffects/Effects/ModifyLungGas.cs
Normal file
49
Content.Server/EntityEffects/Effects/ModifyLungGas.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.EntityEffects;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class ModifyLungGas : EntityEffect
|
||||
{
|
||||
[DataField("ratios", required: true)]
|
||||
private Dictionary<Gas, float> _ratios = default!;
|
||||
|
||||
// JUSTIFICATION: This is internal magic that players never directly interact with.
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> null;
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
|
||||
LungComponent? lung;
|
||||
float amount = 1f;
|
||||
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent<LungComponent>(reagentArgs.OrganEntity, out var organLung))
|
||||
return;
|
||||
lung = organLung;
|
||||
amount = reagentArgs.Quantity.Float();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent<LungComponent>(args.TargetEntity, out var organLung)) //Likely needs to be modified to ensure it works correctly
|
||||
return;
|
||||
lung = organLung;
|
||||
}
|
||||
|
||||
if (lung != null)
|
||||
{
|
||||
foreach (var (gas, ratio) in _ratios)
|
||||
{
|
||||
var quantity = ratio * amount / Atmospherics.BreathMolesToReagentMultiplier;
|
||||
if (quantity < 0)
|
||||
quantity = Math.Max(quantity, -lung.Air[(int) gas]);
|
||||
lung.Air.AdjustMoles(gas, quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Content.Server/EntityEffects/Effects/MovespeedModifier.cs
Normal file
78
Content.Server/EntityEffects/Effects/MovespeedModifier.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
/// <summary>
|
||||
/// Default metabolism for stimulants and tranqs. Attempts to find a MovementSpeedModifier on the target,
|
||||
/// adding one if not there and to change the movespeed
|
||||
/// </summary>
|
||||
public sealed partial class MovespeedModifier : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// How much the entities' walk speed is multiplied by.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float WalkSpeedModifier { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// How much the entities' run speed is multiplied by.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float SprintSpeedModifier { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// How long the modifier applies (in seconds).
|
||||
/// Is scaled by reagent amount if used with an EntityEffectReagentArgs.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float StatusLifetime = 2f;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
{
|
||||
return Loc.GetString("reagent-effect-guidebook-movespeed-modifier",
|
||||
("chance", Probability),
|
||||
("walkspeed", WalkSpeedModifier),
|
||||
("time", StatusLifetime));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove reagent at set rate, changes the movespeed modifiers and adds a MovespeedModifierMetabolismComponent if not already there.
|
||||
/// </summary>
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var status = args.EntityManager.EnsureComponent<MovespeedModifierMetabolismComponent>(args.TargetEntity);
|
||||
|
||||
// Only refresh movement if we need to.
|
||||
var modified = !status.WalkSpeedModifier.Equals(WalkSpeedModifier) ||
|
||||
!status.SprintSpeedModifier.Equals(SprintSpeedModifier);
|
||||
|
||||
status.WalkSpeedModifier = WalkSpeedModifier;
|
||||
status.SprintSpeedModifier = SprintSpeedModifier;
|
||||
|
||||
// only going to scale application time
|
||||
var statusLifetime = StatusLifetime;
|
||||
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
statusLifetime *= reagentArgs.Scale.Float();
|
||||
}
|
||||
|
||||
IncreaseTimer(status, statusLifetime);
|
||||
|
||||
if (modified)
|
||||
args.EntityManager.System<MovementSpeedModifierSystem>().RefreshMovementSpeedModifiers(args.TargetEntity);
|
||||
}
|
||||
public void IncreaseTimer(MovespeedModifierMetabolismComponent status, float time)
|
||||
{
|
||||
var gameTiming = IoCManager.Resolve<IGameTiming>();
|
||||
|
||||
var offsetTime = Math.Max(status.ModifierTimer.TotalSeconds, gameTiming.CurTime.TotalSeconds);
|
||||
|
||||
status.ModifierTimer = TimeSpan.FromSeconds(offsetTime + time);
|
||||
status.Dirty();
|
||||
}
|
||||
}
|
||||
32
Content.Server/EntityEffects/Effects/Oxygenate.cs
Normal file
32
Content.Server/EntityEffects/Effects/Oxygenate.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class Oxygenate : EntityEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Factor = 1f;
|
||||
|
||||
// JUSTIFICATION: This is internal magic that players never directly interact with.
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> null;
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
|
||||
var multiplier = 1f;
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
multiplier = reagentArgs.Quantity.Float();
|
||||
}
|
||||
|
||||
if (args.EntityManager.TryGetComponent<RespiratorComponent>(args.TargetEntity, out var resp))
|
||||
{
|
||||
var respSys = args.EntityManager.System<RespiratorSystem>();
|
||||
respSys.UpdateSaturation(args.TargetEntity, multiplier * Factor, resp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class Paralyze : ReagentEffect
|
||||
public sealed partial class Paralyze : EntityEffect
|
||||
{
|
||||
[DataField] public double ParalyzeTime = 2;
|
||||
|
||||
@@ -18,12 +18,16 @@ public sealed partial class Paralyze : ReagentEffect
|
||||
("chance", Probability),
|
||||
("time", ParalyzeTime));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var paralyzeTime = ParalyzeTime;
|
||||
paralyzeTime *= args.Scale;
|
||||
|
||||
args.EntityManager.System<StunSystem>().TryParalyze(args.SolutionEntity, TimeSpan.FromSeconds(paralyzeTime), Refresh);
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
paralyzeTime *= (double)reagentArgs.Scale;
|
||||
}
|
||||
|
||||
args.EntityManager.System<StunSystem>().TryParalyze(args.TargetEntity, TimeSpan.FromSeconds(paralyzeTime), Refresh);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract partial class PlantAdjustAttribute : EntityEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Amount { get; protected set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Localisation key for the name of the adjusted attribute. Used for guidebook descriptions.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public abstract string GuidebookAttributeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the attribute in question is a good thing. Used for guidebook descriptions to determine the color of the number.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public virtual bool GuidebookIsAttributePositive { get; protected set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the plant holder can metabolize the reagent or not. Checks if it has an alive plant by default.
|
||||
/// </summary>
|
||||
/// <param name="plantHolder">The entity holding the plant</param>
|
||||
/// <param name="plantHolderComponent">The plant holder component</param>
|
||||
/// <param name="entityManager">The entity manager</param>
|
||||
/// <param name="mustHaveAlivePlant">Whether to check if it has an alive plant or not</param>
|
||||
/// <returns></returns>
|
||||
public bool CanMetabolize(EntityUid plantHolder, [NotNullWhen(true)] out PlantHolderComponent? plantHolderComponent,
|
||||
IEntityManager entityManager,
|
||||
bool mustHaveAlivePlant = true)
|
||||
{
|
||||
plantHolderComponent = null;
|
||||
|
||||
if (!entityManager.TryGetComponent(plantHolder, out plantHolderComponent)
|
||||
|| mustHaveAlivePlant && (plantHolderComponent.Seed == null || plantHolderComponent.Dead))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
{
|
||||
string color;
|
||||
if (GuidebookIsAttributePositive ^ Amount < 0.0)
|
||||
{
|
||||
color = "green";
|
||||
}
|
||||
else
|
||||
{
|
||||
color = "red";
|
||||
}
|
||||
return Loc.GetString("reagent-effect-guidebook-plant-attribute", ("attribute", Loc.GetString(GuidebookAttributeName)), ("amount", Amount.ToString("0.00")), ("colorName", color), ("chance", Probability));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.EntityEffects;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
public sealed partial class PlantAdjustHealth : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-health";
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
|
||||
plantHolderComp.Health += Amount;
|
||||
plantHolder.CheckHealth(args.TargetEntity, plantHolderComp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
public sealed partial class PlantAdjustMutationLevel : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-level";
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
plantHolderComp.MutationLevel += Amount * plantHolderComp.MutationMod;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustMutationMod : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-mod";
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
plantHolderComp.MutationMod += Amount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustNutrition : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-nutrition";
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager, mustHaveAlivePlant: false))
|
||||
return;
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
|
||||
plantHolder.AdjustNutrient(args.TargetEntity, Amount, plantHolderComp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustPests : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-pests";
|
||||
public override bool GuidebookIsAttributePositive { get; protected set; } = false;
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
plantHolderComp.PestLevel += Amount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustToxins : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-toxins";
|
||||
public override bool GuidebookIsAttributePositive { get; protected set; } = false;
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
plantHolderComp.Toxins += Amount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustWater : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-water";
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager, mustHaveAlivePlant: false))
|
||||
return;
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
|
||||
plantHolder.AdjustWater(args.TargetEntity, Amount, plantHolderComp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAdjustWeeds : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-weeds";
|
||||
public override bool GuidebookIsAttributePositive { get; protected set; } = false;
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
plantHolderComp.WeedLevel += Amount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlantAffectGrowth : PlantAdjustAttribute
|
||||
{
|
||||
public override string GuidebookAttributeName { get; set; } = "plant-attribute-growth";
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
|
||||
return;
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
|
||||
plantHolder.AffectGrowth(args.TargetEntity, (int) Amount, plantHolderComp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class PlantCryoxadone : EntityEffect
|
||||
{
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.TargetEntity, out PlantHolderComponent? plantHolderComp)
|
||||
|| plantHolderComp.Seed == null || plantHolderComp.Dead)
|
||||
return;
|
||||
|
||||
var deviation = 0;
|
||||
var seed = plantHolderComp.Seed;
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
if (plantHolderComp.Age > seed.Maturation)
|
||||
deviation = (int) Math.Max(seed.Maturation - 1, plantHolderComp.Age - random.Next(7, 10));
|
||||
else
|
||||
deviation = (int) (seed.Maturation / seed.GrowthStages);
|
||||
plantHolderComp.Age -= deviation;
|
||||
plantHolderComp.SkipAging++;
|
||||
plantHolderComp.ForceUpdate = true;
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-cryoxadone", ("chance", Probability));
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class PlantDiethylamine : EntityEffect
|
||||
{
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.TargetEntity, out PlantHolderComponent? plantHolderComp)
|
||||
|| plantHolderComp.Seed == null || plantHolderComp.Dead ||
|
||||
plantHolderComp.Seed.Immutable)
|
||||
return;
|
||||
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
|
||||
if (random.Prob(0.1f))
|
||||
{
|
||||
plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
|
||||
plantHolderComp.Seed.Lifespan++;
|
||||
}
|
||||
|
||||
if (random.Prob(0.1f))
|
||||
{
|
||||
plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
|
||||
plantHolderComp.Seed.Endurance++;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-diethylamine", ("chance", Probability));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class PlantPhalanximine : EntityEffect
|
||||
{
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.TargetEntity, out PlantHolderComponent? plantHolderComp)
|
||||
|| plantHolderComp.Seed == null || plantHolderComp.Dead ||
|
||||
plantHolderComp.Seed.Immutable)
|
||||
return;
|
||||
|
||||
plantHolderComp.Seed.Viable = true;
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-phalanximine", ("chance", Probability));
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Server.Botany.Systems;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
|
||||
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class RobustHarvest : EntityEffect
|
||||
{
|
||||
[DataField]
|
||||
public int PotencyLimit = 50;
|
||||
|
||||
[DataField]
|
||||
public int PotencyIncrease = 3;
|
||||
|
||||
[DataField]
|
||||
public int PotencySeedlessThreshold = 30;
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (!args.EntityManager.TryGetComponent(args.TargetEntity, out PlantHolderComponent? plantHolderComp)
|
||||
|| plantHolderComp.Seed == null || plantHolderComp.Dead ||
|
||||
plantHolderComp.Seed.Immutable)
|
||||
return;
|
||||
|
||||
|
||||
var plantHolder = args.EntityManager.System<PlantHolderSystem>();
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
|
||||
if (plantHolderComp.Seed.Potency < PotencyLimit)
|
||||
{
|
||||
plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
|
||||
plantHolderComp.Seed.Potency = Math.Min(plantHolderComp.Seed.Potency + PotencyIncrease, PotencyLimit);
|
||||
|
||||
if (plantHolderComp.Seed.Potency > PotencySeedlessThreshold)
|
||||
{
|
||||
plantHolderComp.Seed.Seedless = true;
|
||||
}
|
||||
}
|
||||
else if (plantHolderComp.Seed.Yield > 1 && random.Prob(0.1f))
|
||||
{
|
||||
// Too much of a good thing reduces yield
|
||||
plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
|
||||
plantHolderComp.Seed.Yield--;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-robust-harvest", ("seedlesstreshold", PotencySeedlessThreshold), ("limit", PotencyLimit), ("increase", PotencyIncrease), ("chance", Probability));
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
using Content.Server.Polymorph.Components;
|
||||
using Content.Server.Polymorph.Systems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Polymorph;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Content.Shared.EntityEffects;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
public sealed partial class Polymorph : ReagentEffect
|
||||
public sealed partial class Polymorph : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// What polymorph prototype is used on effect
|
||||
@@ -20,10 +21,10 @@ public sealed partial class Polymorph : ReagentEffect
|
||||
("chance", Probability), ("entityname",
|
||||
prototype.Index<EntityPrototype>(prototype.Index<PolymorphPrototype>(PolymorphPrototype).Configuration.Entity).Name));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var entityManager = args.EntityManager;
|
||||
var uid = args.SolutionEntity;
|
||||
var uid = args.TargetEntity;
|
||||
var polySystem = entityManager.System<PolymorphSystem>();
|
||||
|
||||
// Make it into a prototype
|
||||
@@ -1,12 +1,11 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
public sealed partial class PopupMessage : ReagentEffect
|
||||
public sealed partial class PopupMessage : EntityEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public string[] Messages = default!;
|
||||
@@ -21,20 +20,30 @@ namespace Content.Server.Chemistry.ReagentEffects
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> null;
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var popupSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedPopupSystem>();
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
|
||||
var msg = random.Pick(Messages);
|
||||
var msgArgs = new (string, object)[] {
|
||||
("entity", args.SolutionEntity),
|
||||
("organ", args.OrganEntity.GetValueOrDefault()),
|
||||
var msgArgs = new (string, object)[]
|
||||
{
|
||||
("entity", args.TargetEntity),
|
||||
};
|
||||
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
msgArgs = new (string, object)[]
|
||||
{
|
||||
("entity", reagentArgs.TargetEntity),
|
||||
("organ", reagentArgs.OrganEntity.GetValueOrDefault()),
|
||||
};
|
||||
}
|
||||
|
||||
if (Type == PopupRecipients.Local)
|
||||
popupSys.PopupEntity(Loc.GetString(msg, msgArgs), args.SolutionEntity, args.SolutionEntity, VisualType);
|
||||
popupSys.PopupEntity(Loc.GetString(msg, msgArgs), args.TargetEntity, args.TargetEntity, VisualType);
|
||||
else if (Type == PopupRecipients.Pvs)
|
||||
popupSys.PopupEntity(Loc.GetString(msg, msgArgs), args.SolutionEntity, VisualType);
|
||||
popupSys.PopupEntity(Loc.GetString(msg, msgArgs), args.TargetEntity, VisualType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Server.Atmos.Rotting;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
/// <summary>
|
||||
/// Reduces the rotting accumulator on the patient, making them revivable.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ReduceRotting : ReagentEffect
|
||||
public sealed partial class ReduceRotting : EntityEffect
|
||||
{
|
||||
[DataField("seconds")]
|
||||
public double RottingAmount = 10;
|
||||
@@ -18,14 +19,17 @@ namespace Content.Server.Chemistry.ReagentEffects
|
||||
=> Loc.GetString("reagent-effect-guidebook-reduce-rotting",
|
||||
("chance", Probability),
|
||||
("time", RottingAmount));
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.Scale != 1f)
|
||||
return;
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
if (reagentArgs.Scale != 1f)
|
||||
return;
|
||||
}
|
||||
|
||||
var rottingSys = args.EntityManager.EntitySysManager.GetEntitySystem<RottingSystem>();
|
||||
|
||||
rottingSys.ReduceAccumulator(args.SolutionEntity, TimeSpan.FromSeconds(RottingAmount));
|
||||
rottingSys.ReduceAccumulator(args.TargetEntity, TimeSpan.FromSeconds(RottingAmount));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
using Content.Server.Traits.Assorted;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects;
|
||||
namespace Content.Server.EntityEffects.Effects;
|
||||
|
||||
/// <summary>
|
||||
/// Reset narcolepsy timer
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ResetNarcolepsy : ReagentEffect
|
||||
public sealed partial class ResetNarcolepsy : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The # of seconds the effect resets the narcolepsy timer to
|
||||
@@ -20,11 +21,12 @@ public sealed partial class ResetNarcolepsy : ReagentEffect
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-reset-narcolepsy", ("chance", Probability));
|
||||
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.Scale != 1f)
|
||||
return;
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
if (reagentArgs.Scale != 1f)
|
||||
return;
|
||||
|
||||
args.EntityManager.EntitySysManager.GetEntitySystem<NarcolepsySystem>().AdjustNarcolepsyTimer(args.SolutionEntity, TimerReset);
|
||||
args.EntityManager.EntitySysManager.GetEntitySystem<NarcolepsySystem>().AdjustNarcolepsyTimer(args.TargetEntity, TimerReset);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,40 @@
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.ReagentEffects
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to find a HungerComponent on the target,
|
||||
/// and to update it's hunger values.
|
||||
/// </summary>
|
||||
public sealed partial class SatiateHunger : ReagentEffect
|
||||
public sealed partial class SatiateHunger : EntityEffect
|
||||
{
|
||||
private const float DefaultNutritionFactor = 3.0f;
|
||||
|
||||
/// <summary>
|
||||
/// How much hunger is satiated when 1u of the reagent is metabolized
|
||||
/// How much hunger is satiated.
|
||||
/// Is multiplied by quantity if used with EntityEffectReagentArgs.
|
||||
/// </summary>
|
||||
[DataField("factor")] public float NutritionFactor { get; set; } = DefaultNutritionFactor;
|
||||
|
||||
//Remove reagent at set rate, satiate hunger if a HungerComponent can be found
|
||||
public override void Effect(ReagentEffectArgs args)
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var entman = args.EntityManager;
|
||||
if (!entman.TryGetComponent(args.SolutionEntity, out HungerComponent? hunger))
|
||||
if (!entman.TryGetComponent(args.TargetEntity, out HungerComponent? hunger))
|
||||
return;
|
||||
entman.System<HungerSystem>().ModifyHunger(args.SolutionEntity, NutritionFactor * (float) args.Quantity, hunger);
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
entman.System<HungerSystem>().ModifyHunger(reagentArgs.TargetEntity, NutritionFactor * (float) reagentArgs.Quantity, hunger);
|
||||
}
|
||||
else
|
||||
{
|
||||
entman.System<HungerSystem>().ModifyHunger(args.TargetEntity, NutritionFactor, hunger);
|
||||
}
|
||||
}
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user