Reactive 3.0 (#5443)

* probably scrapping this

* reimpl old behavior

* misc fixes and initial yaml

* works basically first try
This commit is contained in:
mirrorcult
2021-11-22 02:17:35 -07:00
committed by GitHub
parent 8b47d0f43f
commit e40c9bc427
17 changed files with 152 additions and 71 deletions

View File

@@ -37,7 +37,7 @@ namespace Content.Server.Chemistry.Components
internals.AreInternalsWorking())
return;
var chemistry = EntitySystem.Get<ChemistrySystem>();
var chemistry = EntitySystem.Get<ReactiveSystem>();
var cloneSolution = solution.Clone();
var transferAmount = FixedPoint2.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.EmptyVolume);
var transferSolution = cloneSolution.SplitSolution(transferAmount);

View File

@@ -126,7 +126,7 @@ namespace Content.Server.Chemistry.Components
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner.Uid, SolutionName, out var solution))
return;
var chemistry = EntitySystem.Get<ChemistrySystem>();
var chemistry = EntitySystem.Get<ReactiveSystem>();
var mapGrid = MapManager.GetGrid(Owner.Transform.GridID);
var tile = mapGrid.GetTileRef(Owner.Transform.Coordinates.ToVector2i(Owner.EntityManager, MapManager));

View File

@@ -17,7 +17,7 @@ namespace Content.Server.Nutrition.EntitySystems
{
public partial class SmokingSystem : EntitySystem
{
[Dependency] private readonly ChemistrySystem _chemistrySystem = default!;
[Dependency] private readonly ReactiveSystem _reactiveSystem = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
private const float UpdateTimer = 3f;
@@ -98,7 +98,7 @@ namespace Content.Server.Nutrition.EntitySystems
!containerManager.Owner.TryGetComponent(out BloodstreamComponent? bloodstream))
continue;
_chemistrySystem.ReactionEntity(containerManager.Owner.Uid, ReactionMethod.Ingestion, inhaledSolution);
_reactiveSystem.ReactionEntity(containerManager.Owner.Uid, ReactionMethod.Ingestion, inhaledSolution);
bloodstream.TryTransferSolution(inhaledSolution);
}

View File

@@ -334,7 +334,7 @@ namespace Content.Shared.Chemistry.Components
public void DoEntityReaction(EntityUid uid, ReactionMethod method)
{
var chemistry = EntitySystem.Get<ChemistrySystem>();
var chemistry = EntitySystem.Get<ReactiveSystem>();
foreach (var (reagentId, quantity) in Contents.ToArray())
{

View File

@@ -1,24 +1,36 @@
using System;
using System.Collections.Generic;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
namespace Content.Shared.Chemistry.Reaction
namespace Content.Shared.Chemistry.Reaction;
[RegisterComponent]
public class ReactiveComponent : Component
{
[RegisterComponent]
public class ReactiveComponent : Component
{
public override string Name => "Reactive";
[DataField("reactions", required: true, readOnly: true, serverOnly: true)]
public List<ReactiveReagentEffectEntry> Reactions { get; } = default!;
}
/// <summary>
/// A dictionary of reactive groups -> methods that work on them.
/// </summary>
[DataField("groups", readOnly: true, serverOnly: true,
customTypeSerializer:
typeof(PrototypeIdDictionarySerializer<HashSet<ReactionMethod>, ReactiveGroupPrototype>))]
public Dictionary<string, HashSet<ReactionMethod>>? ReactiveGroups;
[DataDefinition]
public class ReactiveReagentEffectEntry
{
/// <summary>
/// Special reactions that this prototype can specify, outside of any that reagents already apply.
/// Useful for things like monkey cubes, which have a really prototype-specific effect.
/// </summary>
[DataField("reactions", true, serverOnly: true)]
public List<ReactiveReagentEffectEntry>? Reactions;
}
[DataDefinition]
public class ReactiveReagentEffectEntry
{
[DataField("methods")]
public HashSet<ReactionMethod> Methods = default!;
@@ -27,5 +39,7 @@ namespace Content.Shared.Chemistry.Reaction
[DataField("effects", required: true)]
public List<ReagentEffect> Effects = default!;
}
[DataField("groups", required: true, readOnly: true, serverOnly: true,
customTypeSerializer:typeof(PrototypeIdDictionarySerializer<HashSet<ReactionMethod>, ReactiveGroupPrototype>))]
public Dictionary<string, HashSet<ReactionMethod>> ReactiveGroups { get; } = default!;
}

View File

@@ -0,0 +1,11 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Chemistry.Reaction;
[Prototype("reactiveGroup")]
public class ReactiveGroupPrototype : IPrototype
{
[DataField("id", required: true)]
public string ID { get; } = default!;
}

View File

@@ -11,7 +11,7 @@ using Robust.Shared.Random;
namespace Content.Shared.Chemistry
{
[UsedImplicitly]
public partial class ChemistrySystem : EntitySystem
public class ReactiveSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
@@ -40,6 +40,33 @@ namespace Content.Shared.Chemistry
var args = new ReagentEffectArgs(uid, null, source, reagent,
source?.GetReagentQuantity(reagent.ID) ?? reactVolume, EntityManager, method);
// First, check if the reagent wants to apply any effects.
if (reagent.ReactiveEffects != null && reactive.ReactiveGroups != null)
{
foreach (var (key, val) in reagent.ReactiveEffects)
{
if (!val.Methods.Contains(method))
continue;
if (!reactive.ReactiveGroups.ContainsKey(key))
continue;
if (!reactive.ReactiveGroups[key].Contains(method))
continue;
foreach (var effect in val.Effects)
{
if (!effect.ShouldApply(args, _robustRandom))
continue;
effect.Effect(args);
}
}
}
// Then, check if the prototype has any effects it can apply as well.
if (reactive.Reactions != null)
{
foreach (var entry in reactive.Reactions)
{
if (!entry.Methods.Contains(method))
@@ -58,4 +85,5 @@ namespace Content.Shared.Chemistry
}
}
}
}
}

View File

@@ -23,15 +23,6 @@ namespace Content.Shared.Chemistry.Reagent
[DataDefinition]
public class ReagentPrototype : IPrototype, IInheritingPrototype
{
[DataField("metabolisms", serverOnly: true, customTypeSerializer: typeof(PrototypeIdDictionarySerializer<ReagentEffectsEntry, MetabolismGroupPrototype>))]
public Dictionary<string, ReagentEffectsEntry>? Metabolisms = null;
[DataField("tileReactions", serverOnly: true)]
private readonly List<ITileReaction> _tileReactions = new(0);
[DataField("plantMetabolism", serverOnly: true)]
private readonly List<ReagentEffect> _plantMetabolism = new(0);
[ViewVariables]
[DataField("id", required: true)]
public string ID { get; } = default!;
@@ -64,9 +55,17 @@ namespace Content.Shared.Chemistry.Reagent
[DataField("spritePath")]
public string SpriteReplacementPath { get; } = string.Empty;
//List of metabolism effects this reagent has, should really only be used server-side.
public IReadOnlyList<ITileReaction> TileReactions => _tileReactions;
public IReadOnlyList<ReagentEffect> PlantMetabolism => _plantMetabolism;
[DataField("metabolisms", serverOnly: true, customTypeSerializer: typeof(PrototypeIdDictionarySerializer<ReagentEffectsEntry, MetabolismGroupPrototype>))]
public Dictionary<string, ReagentEffectsEntry>? Metabolisms = null;
[DataField("reactiveEffects", serverOnly: true, customTypeSerializer:typeof(PrototypeIdDictionarySerializer<ReactiveReagentEffectEntry, ReactiveGroupPrototype>))]
public Dictionary<string, ReactiveReagentEffectEntry>? ReactiveEffects = null;
[DataField("tileReactions", serverOnly: true)]
public readonly List<ITileReaction> TileReactions = new(0);
[DataField("plantMetabolism", serverOnly: true)]
public readonly List<ReagentEffect> PlantMetabolisms = new(0);
/// <summary>
/// If the substance color is too dark we user a lighter version to make the text color readable when the user examines a solution.
@@ -93,7 +92,7 @@ namespace Content.Shared.Chemistry.Reagent
if (tile.Tile.IsEmpty)
return removed;
foreach (var reaction in _tileReactions)
foreach (var reaction in TileReactions)
{
removed += reaction.TileReact(tile, this, reactVolume - removed);
@@ -115,7 +114,7 @@ namespace Content.Shared.Chemistry.Reagent
var entMan = IoCManager.Resolve<IEntityManager>();
var random = IoCManager.Resolve<IRobustRandom>();
var args = new ReagentEffectArgs(plantHolder.Value, null, solution, this, amount.Quantity, entMan, null);
foreach (var plantMetabolizable in _plantMetabolism)
foreach (var plantMetabolizable in PlantMetabolisms)
{
if (!plantMetabolizable.ShouldApply(args, random))
continue;
@@ -140,4 +139,14 @@ namespace Content.Shared.Chemistry.Reagent
[DataField("effects", required: true)]
public ReagentEffect[] Effects = default!;
}
[DataDefinition]
public class ReactiveReagentEffectEntry
{
[DataField("methods", required: true)]
public HashSet<ReactionMethod> Methods = default!;
[DataField("effects", required: true)]
public ReagentEffect[] Effects = default!;
}
}

View File

@@ -0,0 +1,5 @@
- type: reactiveGroup
id: Flammable
- type: reactiveGroup
id: Extinguish

View File

@@ -5,15 +5,9 @@
suffix: AI
components:
- type: Reactive
reactions:
- reagents: [Water]
methods: [Touch]
effects:
- !type:ExtinguishReaction
- reagents: [WeldingFuel, Thermite, Plasma, Ethanol]
methods: [Touch]
effects:
- !type:FlammableReaction
groups:
Flammable: [Touch]
Extinguish: [Touch]
- type: UtilityAI
behaviorSets:
# - Clothing

View File

@@ -11,15 +11,10 @@
- CanPilot
- FootstepSound
- type: Reactive
groups:
Flammable: [ Touch ]
Extinguish: [ Touch ]
reactions:
- reagents: [Water]
methods: [Touch]
effects:
- !type:ExtinguishReaction
- reagents: [WeldingFuel, Thermite, Plasma, Ethanol]
methods: [Touch]
effects:
- !type:FlammableReaction
- reagents: [Water, SpaceCleaner]
methods: [Touch]
effects:

View File

@@ -60,14 +60,12 @@
- type: reagent
id: Ethanol
name: ethanol
parent: BaseAlcohol
desc: A simple alcohol, makes you drunk if consumed, flammable.
physicalDesc: strong-smelling
color: "#b05b3c"
boilingPoint: 78.2
meltingPoint: -114.1
tileReactions:
- !type:FlammableTileReaction
temperatureMultiplier: 1.35
metabolisms:
Poison:
effects:

View File

@@ -6,6 +6,11 @@
effects:
- !type:SatiateThirst
factor: 3
reactiveEffects:
Extinguish:
methods: [ Touch ]
effects:
- !type:ExtinguishReaction
plantMetabolism:
- !type:PlantAdjustWater
amount: 1
@@ -38,6 +43,11 @@
effects:
- !type:SatiateThirst
factor: 2
reactiveEffects:
Flammable:
methods: [ Touch ]
effects:
- !type:FlammableReaction
tileReactions:
- !type:FlammableTileReaction
temperatureMultiplier: 1.35

View File

@@ -1,6 +1,15 @@
- type: reagent
id: BasePyrotechnic
reactiveEffects:
Flammable:
methods: [ Touch ]
effects:
- !type:FlammableReaction
- type: reagent
id: Thermite
name: thermite
parent: BasePyrotechnic
desc: A mixture that becomes extremely hot when ignited, and which can burn straight through walls when applied and ignited. It'll slowly inflict burn damage to anybody dumb enough to ingest it, but can't be ignited inside inside said dumb person.
physicalDesc: grainy
color: "#757245"
@@ -20,6 +29,7 @@
- type: reagent
id: FoamingAgent
name: foaming agent
parent: BasePyrotechnic
desc: Makes foam such as that's required in metal foam grenades.
physicalDesc: foamy
color: "#215263"
@@ -29,6 +39,7 @@
- type: reagent
id: WeldingFuel
name: welding fuel
parent: BasePyrotechnic
desc: Used by welders to weld.
physicalDesc: oily
color: "#a76b1c"
@@ -40,6 +51,7 @@
- type: reagent
id: Fluorosurfactant
name: fluorosurfactant
parent: BasePyrotechnic
desc: A perfluoronated sulfonic acid that forms a foam when mixed with water.
physicalDesc: opaque
color: "#9e6b38"

View File

@@ -115,6 +115,11 @@
- !type:RemoveReagent
reagent: Inaprovaline
amount: 2
reactiveEffects:
Flammable:
methods: [ Touch ]
effects:
- !type:FlammableReaction
- type: reagent
id: UnstableMutagen