Skip to content

Commit

Permalink
Cryogenics: restrict cryo pods to cryo meds, restore limited metaboli…
Browse files Browse the repository at this point in the history
…sm (#1533)

* Cleanup, revised Solution split

* French spacing

* cryo pod: only extract cryogenics chems from soln

* Add Cryogenic metabolism group, add to organs

* Cleanup comments, "PerReagent" soln split & docs

* Comment accuracy

* SplitSolutionPerReagent: suggested fixes

---------

Co-authored-by: Whatstone <whatstone3@gmail.com>
  • Loading branch information
whatston3 and Whatstone authored Jun 21, 2024
1 parent 235e359 commit 39591e9
Show file tree
Hide file tree
Showing 25 changed files with 173 additions and 76 deletions.
10 changes: 0 additions & 10 deletions Content.Server/Body/Components/MetabolizerComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,6 @@ public sealed partial class MetabolizerComponent : Component
[DataField("maxReagents")]
public int MaxReagentsProcessable = 3;

/// <summary>
/// Frontier
///
/// How many poisons can this metabolizer process at once?
/// Used to nerf 'stacked poisons' where having 5+ different poisons in a syringe, even at low
/// quantity, would be muuuuch better than just one poison acting.
/// </summary>
[DataField("maxPoisons")]
public int MaxPoisonsProcessable = 3;

/// <summary>
/// A list of metabolism groups that this metabolizer will act on, in order of precedence.
/// </summary>
Expand Down
17 changes: 9 additions & 8 deletions Content.Server/Body/Systems/MetabolizerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ private void TryMetabolize(Entity<MetabolizerComponent, OrganComponent?, Solutio
var list = solution.Contents.ToArray();
_random.Shuffle(list);

int poisons = 0; // frontier modified
int reagents = 0;
foreach (var (reagent, quantity) in list)
{
if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.Prototype, out var proto))
Expand All @@ -158,10 +158,11 @@ private void TryMetabolize(Entity<MetabolizerComponent, OrganComponent?, Solutio

continue;
}
// frontier modified
// Already processed all poisons, skip to the next reagent.
if (poisons >= ent.Comp1.MaxPoisonsProcessable && proto.Metabolisms.ContainsKey("Poison"))

// Frontier: all cryogenic reagents in the solution should be processed, others should be limited (buff cryo meds)
if (reagents >= ent.Comp1.MaxReagentsProcessable && !proto.Metabolisms.ContainsKey("Cryogenic"))
continue;
// End Frontier


// loop over all our groups and see which ones apply
Expand Down Expand Up @@ -219,10 +220,10 @@ private void TryMetabolize(Entity<MetabolizerComponent, OrganComponent?, Solutio
if (mostToRemove > FixedPoint2.Zero)
{
solution.RemoveReagent(reagent, mostToRemove);
// frontier modified
// We have processed a poison, so count it towards the cap
if (proto.Metabolisms.ContainsKey("Poison"))
poisons++;
// Frontier: do not count cryogenics chems against the reagent limit (to buff cryo meds)
if (!proto.Metabolisms.ContainsKey("Cryogenic"))
reagents++;
// End Frontier
}
}

Expand Down
13 changes: 8 additions & 5 deletions Content.Server/Medical/CryoPodSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public sealed partial class CryoPodSystem : SharedCryoPodSystem
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;

// Frontier: keep a list of cryogenics reagents. The pod will only filter these out from the provided solution.
private static readonly string[] CryogenicsReagents = ["Cryoxadone", "Aloxadone", "Doxarubixadone", "Opporozidone", "Necrosol", "Traumoxadone", "Stelloxadone"];

public override void Initialize()
{
base.Initialize();
Expand Down Expand Up @@ -115,14 +118,14 @@ public override void Update(float frameTime)
continue;
}

// frontier

// Frontier
// Filter out a fixed amount of each reagent from the cryo pod's beaker
var solutionToInject = _solutionContainerSystem.SplitSolutionReagentsEvenly(containerSolution.Value, cryoPod.BeakerTransferAmount);
// for every .25 units used, .5 units per second are added to the body, making cryo-pod more efficient than injections
solutionToInject.ScaleSolution(cryoPod.PotencyMultiplier);
var solutionToInject = _solutionContainerSystem.SplitSolutionPerReagentWithOnly(containerSolution.Value, cryoPod.BeakerTransferAmount, CryogenicsReagents);

// End frontier
// For every .25 units used, .5 units per second are added to the body, making cryo-pod more efficient than injections.
solutionToInject.ScaleSolution(cryoPod.PotencyMultiplier);
// End Frontier

_bloodstreamSystem.TryAddToChemicals(patient.Value, solutionToInject, bloodstream);
_reactiveSystem.DoEntityReaction(patient.Value, solutionToInject, ReactionMethod.Injection);
Expand Down
130 changes: 98 additions & 32 deletions Content.Shared/Chemistry/Components/Solution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -606,11 +606,12 @@ public Solution SplitSolutionWithOnly(FixedPoint2 toTake, params string[] includ

return sol;
}

/// <summary>
/// splits the solution taking the specified amount of reagents proportionally to their quantity.
/// Splits a solution, taking the specified amount of reagents proportionally to their quantity.
/// </summary>
/// <param name="toTake">The total amount of solution to remove and return.</param>
/// <returns>a new solution of equal proportions to the original solution</returns>
/// <returns>A new solution of equal proportions to the original.</returns>
public Solution SplitSolution(FixedPoint2 toTake)
{
if (toTake <= FixedPoint2.Zero)
Expand Down Expand Up @@ -674,58 +675,123 @@ public Solution SplitSolution(FixedPoint2 toTake)
return newSolution;
}

// Frontier: cryogenics per-reagent filter function (#1443, #1533)
/// <summary>
/// Frontier
/// splits the solution taking up to the specified amount of each reagent from the solution.
/// If the solution has less of a reagent than the specified amount, it will take all of that reagent.
/// Splits a solution, taking the specified amount of each reagent from the solution.
/// If any reagent in the solution has less volume than specified, it will all be transferred into the new solution.
/// </summary>
/// <param name="toTakePer">How much of each reagent to take</param>
/// <returns>a new solution containing the reagents taken from the original solution</returns>
public Solution SplitSolutionReagentsEvenly(FixedPoint2 toTakePer)
/// <param name="toTakePer">How much of each reagent to take.</param>
/// <returns>A new solution containing the reagents taken from the original solution.</returns>
public Solution SplitSolutionPerReagent(FixedPoint2 toTakePer)
{
var splitSolution = new Solution();

if (toTakePer <= FixedPoint2.Zero)
return splitSolution;
var reagentsCount = Contents.Count;
var reagentsToRemove = new List<ReagentQuantity>();
for (var i = 0; i < reagentsCount; i++)
return new Solution();

var origVol = Volume;
Solution newSolution = new Solution(Contents.Count) { Temperature = Temperature };

for (var i = Contents.Count - 1; i >= 0; i--) // iterate backwards because of remove swap.
{
var currentReagent = Contents[i];
var (reagent, quantity) = Contents[i];

if (currentReagent.Quantity <= FixedPoint2.Zero)
// If the reagent has more than enough volume to remove, no need to remove it from the list.
if (quantity > toTakePer)
{
reagentsToRemove.Add(currentReagent);
continue;
Contents[i] = new ReagentQuantity(reagent, quantity - toTakePer);
newSolution.Contents.Add(new ReagentQuantity(reagent, toTakePer));
Volume -= toTakePer;
}
else
{
Contents.RemoveSwap(i);
//Only add positive quantities to our new solution.
if (quantity > 0)
{
newSolution.Contents.Add(new ReagentQuantity(reagent, quantity));
Volume -= quantity;
}
}
}

// If old solution is empty, invalidate old solution and transfer all volume to new.
if (Volume <= 0)
{
RemoveAllSolution();
newSolution.Volume = origVol;
}
else
{
newSolution.Volume = origVol - Volume;
_heatCapacityDirty = true;
}
newSolution._heatCapacityDirty = true;

ValidateSolution();
newSolution.ValidateSolution();

return newSolution;
}

/// <summary>
/// Splits a solution, taking the specified amount of each reagent specified in reagents from the solution.
/// If any reagent in the solution has less volume than specified, it will all be transferred into the new solution.
/// </summary>
/// <param name="toTakePer">How much of each reagent to take.</param>
/// <returns>A new solution containing the reagents taken from the original solution.</returns>
public Solution SplitSolutionPerReagentWithOnly(FixedPoint2 toTakePer, params string[] reagents)
{
if (toTakePer <= FixedPoint2.Zero)
return new Solution();

var origVol = Volume;
Solution newSolution = new Solution(Contents.Count) { Temperature = Temperature };

for (var i = Contents.Count - 1; i >= 0; i--) // iterate backwards because of remove swap.
{
var (reagent, quantity) = Contents[i];

// Each reagent to split must be in the set given.
if (!reagents.Contains(reagent.Prototype))
continue;

if (currentReagent.Quantity <= toTakePer)
// If the reagent has more than enough volume to remove, no need to remove it from the list.
if (quantity > toTakePer)
{
splitSolution.AddReagent(currentReagent);
reagentsToRemove.Add(currentReagent);
Contents[i] = new ReagentQuantity(reagent, quantity - toTakePer);
newSolution.Contents.Add(new ReagentQuantity(reagent, toTakePer));
Volume -= toTakePer;
}
else
{
splitSolution.AddReagent(currentReagent.Reagent, toTakePer);
RemoveReagent(currentReagent.Reagent, toTakePer);
Contents.RemoveSwap(i);
//Only add positive quantities to our new solution.
if (quantity > 0)
{
newSolution.Contents.Add(new ReagentQuantity(reagent, quantity));
Volume -= quantity;
}
}
}

foreach (var reagent in reagentsToRemove)
// If old solution is empty, invalidate old solution and transfer all volume to new.
if (Volume <= 0)
{
RemoveReagent(reagent);
}
if (Volume == FixedPoint2.Zero)
RemoveAllSolution();

_heatCapacityDirty = true;
splitSolution._heatCapacityDirty = true;
newSolution.Volume = origVol;
}
else
{
newSolution.Volume = origVol - Volume;
_heatCapacityDirty = true;
}
newSolution._heatCapacityDirty = true;

ValidateSolution();
splitSolution.ValidateSolution();
newSolution.ValidateSolution();

return splitSolution;
return newSolution;
}
// End Frontier

/// <summary>
/// Variant of <see cref="SplitSolution(FixedPoint2)"/> that doesn't return a new solution containing the removed reagents.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,22 +310,40 @@ public Solution SplitSolution(Entity<SolutionComponent> soln, FixedPoint2 quanti
return splitSol;
}

// Frontier: cryogenics filtering functions (#1443)
/// <summary>
/// Frontier
/// Splits a solution removing a specified amount of each reagent, if available.
/// </summary>
/// <param name="soln">The container to split the solution from.</param>
/// <param name="quantity">The amount of each reagent to split.</param>
/// <returns></returns>
public Solution SplitSolutionReagentsEvenly(Entity<SolutionComponent> soln, FixedPoint2 quantity)
/// <returns>The solution that was removed.</returns>
public Solution SplitSolutionPerReagent(Entity<SolutionComponent> soln, FixedPoint2 quantity)
{
var (uid, comp) = soln;
var solution = comp.Solution;

var splitSol = solution.SplitSolutionPerReagent(quantity);
UpdateChemicals(soln);
return splitSol;
}

/// <summary>
/// Splits a solution removing a specified amount of each reagent, if available.
/// </summary>
/// <param name="soln">The container to split the solution from.</param>
/// <param name="quantity">The amount of each reagent to split.</param>
/// <param name="reagents">The list of reagents to split a fixed amount of, if present.</param>
/// <returns>The solution that was removed.</returns>
public Solution SplitSolutionPerReagentWithOnly(Entity<SolutionComponent> soln, FixedPoint2 quantity, params string[] reagents)
{
var (uid, comp) = soln;
var solution = comp.Solution;

var splitSol = solution.SplitSolutionReagentsEvenly(quantity);
var splitSol = solution.SplitSolutionPerReagentWithOnly(quantity, reagents);
UpdateChemicals(soln);
return splitSol;
}
// End Frontier

public Solution SplitStackSolution(Entity<SolutionComponent> soln, FixedPoint2 quantity, int stackCount)
{
Expand Down
5 changes: 3 additions & 2 deletions Content.Shared/Medical/Cryogenics/CryoPodComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,16 @@ public sealed partial class CryoPodComponent : Component
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("beakerTransferAmount")]
public float BeakerTransferAmount = .25f;// Frontier: 1<0.25
public float BeakerTransferAmount = .25f; // Frontier: 1<0.25 (applied per reagent)

// Frontier: more efficient cryogenics (#1443)
/// <summary>
/// Frontier
/// How potent (multiplier) the reagents are when transferred from the beaker to the mob.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("PotencyAmount")]
public float PotencyMultiplier = 2f;
// End Frontier

/// <summary>
/// Delay applied when inserting a mob in the pod.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
metabolism-group-cryogenic = Cryogenic
8 changes: 4 additions & 4 deletions Resources/Locale/en-US/reagents/meta/medicine.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@ reagent-name-bicaridine = bicaridine
reagent-desc-bicaridine = An analgesic which is highly effective at treating brute damage. It's useful for stabilizing people who have been severely beaten, as well as treating less life-threatening injuries.
# Frontier: consistent cryogenics descriptors

reagent-name-cryoxadone = cryoxadone
reagent-desc-cryoxadone = Required for the proper function of cryogenics. Useful in treating asphyxiation and bloodloss, but only works in temperatures under 213K. It can treat and rejuvenate plants when applied in small doses. Works regardless of the patient being alive or dead.
reagent-desc-cryoxadone = A cryogenics chemical. Useful in treating asphyxiation and bloodloss, but only works in temperatures under 213K. It can treat and rejuvenate plants when applied in small doses. Works regardless of the patient being alive or dead.
reagent-name-doxarubixadone = doxarubixadone
reagent-desc-doxarubixadone = A cryogenics chemical. Heals certain types of cellular damage done by Slimes and improper use of other chemicals. Works regardless of the patient being alive or dead.
# End Frontier

reagent-name-dermaline = dermaline
Expand Down Expand Up @@ -134,8 +132,10 @@ reagent-desc-insuzine = Rapidly repairs dead tissue caused by electrocution, but
reagent-name-opporozidone = opporozidone
reagent-desc-opporozidone= A difficult to synthesize cryogenic drug used to regenerate rotting tissue and brain matter.
# Frontier: consistent cryogenics descriptors
reagent-name-necrosol = necrosol
reagent-desc-necrosol = A necrotic substance that seems to be able to heal frozen corpses. It can treat and rejuvenate plants when applied in small doses.
reagent-desc-necrosol = A cryogenics chemical. Heals most organic damage, a true panacea. It can treat and rejuvenate plants when applied in small doses. Works regardless of the patient being alive or dead.
# End Frontier

reagent-name-aloxadone = aloxadone
reagent-desc-aloxadone = A cryogenics chemical. Used to treat severe third degree burns via regeneration of the burnt tissue. Works regardless of the patient being alive or dead.
Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Body/Organs/Animal/animal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
metabolizerTypes: [ Animal ]
groups:
- id: Medicine
- id: Cryogenic # Frontier
- id: Poison
- id: Narcotic

Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Body/Organs/Animal/slimes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- id: Food
- id: Drink
- id: Medicine
- id: Cryogenic # Frontier
- id: Poison
- id: Narcotic
- id: Alcohol
Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Body/Organs/arachnid.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
metabolizerTypes: [Arachnid]
groups:
- id: Medicine
- id: Cryogenic # Frontier
- id: Poison
- id: Narcotic

Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Body/Organs/diona.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
- id: Food
- id: Drink
- id: Medicine
- id: Cryogenic # Frontier
- id: Poison
- id: Narcotic
- id: Alcohol
Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Body/Organs/human.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
metabolizerTypes: [Human]
groups:
- id: Medicine
- id: Cryogenic # Frontier
- id: Poison
- id: Narcotic

Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Body/Organs/moth.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- id: Food
- id: Drink
- id: Medicine
- id: Cryogenic # Frontier
- id: Poison
- id: Narcotic
- id: Alcohol
Loading

0 comments on commit 39591e9

Please sign in to comment.