* LOCKED THE FUCK IN * Forgot this little fella * Crying * All entity effects ported, needs cleanup still * Commit * HEHEHEHAW * Shelve for now * fixe * Big * First big chunk of changes * Big if true * Commit * IT BUILDS!!! * Fix LINTER fails * Cleanup * Scale working, cut down on some evil code * Delete old Entity Effects * Accidentally breaking shit by fixing bugs * Fix a bunch of effects not working * Fix reagent thresholds * Update damage * Wait don't change the gas metabolisms A * Cleanup * more fixes * Eh * Misc fixes and jank * Remove two things, add bullshit, change condition to inverted * Remove unused "Shared" system structure * Namespace fix * merge conflicts/cleanup * More fixes * Guidebook text begins * Shelve * Push * More shit to push * Fix * Fix merg conflicts * BLOOD FOR THE BLOOD GOD!!! * Mild cleanup and lists * Fix localization and comments * Shuffle localization around a bit. * All done? * Nearly everything * Is this the end? * Whoops forgot to remove that TODO * Get rid of some warnings for good measure... * It's done * Should make those virtual in case we want to override them tbqh... * Update Content.Shared/EntityEffects/Effects/Botany/PlantAttributes/PlantDestroySeeds.cs Co-authored-by: Pok <113675512+Pok27@users.noreply.github.com> * Fix test fails real * Add to codeowners * Documentation to everything * Forgot to push whoops * Standardize Condition names * Fix up metabolism a little as a treat * review * add IsServer checks --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> Co-authored-by: Pok <113675512+Pok27@users.noreply.github.com>
123 lines
4.6 KiB
C#
123 lines
4.6 KiB
C#
using Content.Server.Botany.Components;
|
|
using Content.Shared.EntityEffects;
|
|
using Content.Shared.EntityEffects.Effects.Botany.PlantAttributes;
|
|
using Robust.Shared.Random;
|
|
|
|
namespace Content.Server.EntityEffects.Effects.Botany.PlantAttributes;
|
|
|
|
/// <summary>
|
|
/// This system mutates an inputted stat for a PlantHolder, only works for floats, integers, and bools.
|
|
/// </summary>
|
|
/// <inheritdoc cref="EntityEffectSystem{T,TEffect}"/>
|
|
public sealed partial class PlantChangeStatEntityEffectSystem : EntityEffectSystem<PlantHolderComponent, PlantChangeStat>
|
|
{
|
|
// TODO: This is awful. I do not have the strength to refactor this. I want it gone.
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
|
|
|
protected override void Effect(Entity<PlantHolderComponent> entity, ref EntityEffectEvent<PlantChangeStat> args)
|
|
{
|
|
if (entity.Comp.Seed == null || entity.Comp.Dead)
|
|
return;
|
|
|
|
var effect = args.Effect;
|
|
var member = entity.Comp.Seed.GetType().GetField(args.Effect.TargetValue);
|
|
|
|
if (member == null)
|
|
{
|
|
Log.Error($"{ effect.GetType().Name } Error: Member { args.Effect.TargetValue} not found on { entity.Comp.Seed.GetType().Name }. Did you misspell it?");
|
|
return;
|
|
}
|
|
|
|
var currentValObj = member.GetValue(entity.Comp.Seed);
|
|
if (currentValObj == null)
|
|
return;
|
|
|
|
if (member.FieldType == typeof(float))
|
|
{
|
|
var floatVal = (float)currentValObj;
|
|
MutateFloat(ref floatVal, args.Effect.MinValue, args.Effect.MaxValue, args.Effect.Steps);
|
|
member.SetValue(entity.Comp.Seed, floatVal);
|
|
}
|
|
else if (member.FieldType == typeof(int))
|
|
{
|
|
var intVal = (int)currentValObj;
|
|
MutateInt(ref intVal, (int)args.Effect.MinValue, (int)args.Effect.MaxValue, args.Effect.Steps);
|
|
member.SetValue(entity.Comp.Seed, intVal);
|
|
}
|
|
else if (member.FieldType == typeof(bool))
|
|
{
|
|
var boolVal = (bool)currentValObj;
|
|
boolVal = !boolVal;
|
|
member.SetValue(entity.Comp.Seed, boolVal);
|
|
}
|
|
}
|
|
|
|
// Mutate reference 'val' between 'min' and 'max' by pretending the value
|
|
// is representable by a thermometer code with 'bits' number of bits and
|
|
// randomly flipping some of them.
|
|
private void MutateFloat(ref float val, float min, float max, int bits)
|
|
{
|
|
if (min == max)
|
|
{
|
|
val = min;
|
|
return;
|
|
}
|
|
|
|
// Starting number of bits that are high, between 0 and bits.
|
|
// In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded.
|
|
int valInt = (int)MathF.Round((val - min) / (max - min) * bits);
|
|
// val may be outside the range of min/max due to starting prototype values, so clamp.
|
|
valInt = Math.Clamp(valInt, 0, bits);
|
|
|
|
// Probability that the bit flip increases n.
|
|
// The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasive it it.
|
|
// In other words, it tends to go to the middle.
|
|
float probIncrease = 1 - (float)valInt / bits;
|
|
int valIntMutated;
|
|
if (_random.Prob(probIncrease))
|
|
{
|
|
valIntMutated = valInt + 1;
|
|
}
|
|
else
|
|
{
|
|
valIntMutated = valInt - 1;
|
|
}
|
|
|
|
// Set value based on mutated thermometer code.
|
|
float valMutated = Math.Clamp((float)valIntMutated / bits * (max - min) + min, min, max);
|
|
val = valMutated;
|
|
}
|
|
|
|
private void MutateInt(ref int val, int min, int max, int bits)
|
|
{
|
|
if (min == max)
|
|
{
|
|
val = min;
|
|
return;
|
|
}
|
|
|
|
// Starting number of bits that are high, between 0 and bits.
|
|
// In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded.
|
|
int valInt = (int)MathF.Round((val - min) / (max - min) * bits);
|
|
// val may be outside the range of min/max due to starting prototype values, so clamp.
|
|
valInt = Math.Clamp(valInt, 0, bits);
|
|
|
|
// Probability that the bit flip increases n.
|
|
// The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasing it.
|
|
// In other words, it tends to go to the middle.
|
|
float probIncrease = 1 - (float)valInt / bits;
|
|
int valMutated;
|
|
if (_random.Prob(probIncrease))
|
|
{
|
|
valMutated = val + 1;
|
|
}
|
|
else
|
|
{
|
|
valMutated = val - 1;
|
|
}
|
|
|
|
valMutated = Math.Clamp(valMutated, min, max);
|
|
val = valMutated;
|
|
}
|
|
}
|