diff --git a/Content.Server/Botany/SeedPrototype.cs b/Content.Server/Botany/SeedPrototype.cs index b5c748b000..d47bc42f7e 100644 --- a/Content.Server/Botany/SeedPrototype.cs +++ b/Content.Server/Botany/SeedPrototype.cs @@ -1,4 +1,3 @@ -using System.ComponentModel; using Content.Server.Botany.Components; using Content.Server.Botany.Systems; using Content.Shared.Atmos; @@ -7,11 +6,10 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; using Robust.Shared.Utility; +using Robust.Shared.Audio; namespace Content.Server.Botany; - - [Prototype("seed")] public sealed class SeedPrototype : SeedData, IPrototype { @@ -144,6 +142,8 @@ public class SeedData [DataField("weedTolerance")] public float WeedTolerance = 5f; + [DataField("weedHighLevelThreshold")] public float WeedHighLevelThreshold = 10f; + #endregion #region General traits @@ -155,6 +155,8 @@ public class SeedData [DataField("maturation")] public float Maturation; [DataField("production")] public float Production; [DataField("growthStages")] public int GrowthStages = 6; + + [ViewVariables(VVAccess.ReadWrite)] [DataField("harvestRepeat")] public HarvestType HarvestRepeat = HarvestType.NoRepeat; [DataField("potency")] public float Potency = 1f; @@ -208,12 +210,20 @@ public class SeedData [DataField("plantIconState")] public string PlantIconState { get; set; } = "produce"; - [DataField("bioluminescent")] public bool Bioluminescent; + [DataField("screamSound")] + public SoundSpecifier ScreamSound = new SoundPathSpecifier("/Audio/Voice/Human/malescream_1.ogg"); + + [DataField("screaming")] public bool CanScream; + + [DataField("bioluminescent")] public bool Bioluminescent; [DataField("bioluminescentColor")] public Color BioluminescentColor { get; set; } = Color.White; public float BioluminescentRadius = 2f; + [DataField("kudzuPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))] public string KudzuPrototype = "WeakKudzu"; + + [DataField("turnIntoKudzu")] public bool TurnIntoKudzu; [DataField("splatPrototype")] public string? SplatPrototype { get; set; } #endregion @@ -265,6 +275,8 @@ public class SeedData PlantRsi = PlantRsi, PlantIconState = PlantIconState, Bioluminescent = Bioluminescent, + CanScream = CanScream, + TurnIntoKudzu = TurnIntoKudzu, BioluminescentColor = BioluminescentColor, SplatPrototype = SplatPrototype, diff --git a/Content.Server/Botany/Systems/BotanySystem.Produce.cs b/Content.Server/Botany/Systems/BotanySystem.Produce.cs index bc9bfbad8b..552b60a3fb 100644 --- a/Content.Server/Botany/Systems/BotanySystem.Produce.cs +++ b/Content.Server/Botany/Systems/BotanySystem.Produce.cs @@ -1,5 +1,4 @@ using Content.Server.Botany.Components; -using Content.Shared.Chemistry.Components; using Content.Shared.FixedPoint; using Robust.Server.GameObjects; @@ -18,17 +17,17 @@ public sealed partial class BotanySystem sprite.LayerSetState(0, seed.PlantIconState); } - Solution.ReagentQuantity[] reagents = new Solution.ReagentQuantity[seed.Chemicals.Count]; - int i = 0; + var solutionContainer = _solutionContainerSystem.EnsureSolution(uid, produce.SolutionName); + + solutionContainer.RemoveAllSolution(); foreach (var (chem, quantity) in seed.Chemicals) { var amount = FixedPoint2.New(quantity.Min); if (quantity.PotencyDivisor > 0 && seed.Potency > 0) amount += FixedPoint2.New(seed.Potency / quantity.PotencyDivisor); amount = FixedPoint2.New((int) MathHelper.Clamp(amount.Float(), quantity.Min, quantity.Max)); - reagents[i++] = new(chem, amount); + solutionContainer.MaxVolume += amount; + solutionContainer.AddReagent(chem, amount); } - - _solutionContainerSystem.EnsureSolution(uid, produce.SolutionName, reagents); } } diff --git a/Content.Server/Botany/Systems/MutationSystem.cs b/Content.Server/Botany/Systems/MutationSystem.cs index df2b4e3380..b9258494e3 100644 --- a/Content.Server/Botany/Systems/MutationSystem.cs +++ b/Content.Server/Botany/Systems/MutationSystem.cs @@ -19,7 +19,7 @@ public class MutationSystem : EntitySystem public void MutateSeed(SeedData seed, float severity) { // Add up everything in the bits column and put the number here. - const int totalbits = 215; + const int totalbits = 245; // Tolerances (55) MutateFloat(ref seed.NutrientConsumption , 0.05f , 1.2f , 5 , totalbits , severity); @@ -45,13 +45,17 @@ public class MutationSystem : EntitySystem // Kill the plant (30) MutateBool(ref seed.Viable , false , 30 , totalbits , severity); - // Fun (70) + // Fun (90) MutateBool(ref seed.Seedless , true , 10 , totalbits , severity); MutateBool(ref seed.Slip , true , 10 , totalbits , severity); MutateBool(ref seed.Sentient , true , 10 , totalbits , severity); MutateBool(ref seed.Ligneous , true , 10 , totalbits , severity); MutateBool(ref seed.Bioluminescent , true , 10 , totalbits , severity); + MutateBool(ref seed.TurnIntoKudzu , true , 10 , totalbits , severity); + MutateBool(ref seed.CanScream , true , 10 , totalbits , severity); seed.BioluminescentColor = RandomColor(seed.BioluminescentColor, 10, totalbits, severity); + // ConstantUpgade (10) + MutateHarvestType(ref seed.HarvestRepeat , 10 , totalbits , severity); } public SeedData Cross(SeedData a, SeedData b) @@ -85,6 +89,8 @@ public class MutationSystem : EntitySystem CrossBool(ref result.Sentient, a.Sentient); CrossBool(ref result.Ligneous, a.Ligneous); CrossBool(ref result.Bioluminescent, a.Bioluminescent); + CrossBool(ref result.TurnIntoKudzu, a.TurnIntoKudzu); + CrossBool(ref result.CanScream, a.CanScream); result.BioluminescentColor = random(0.5f) ? a.BioluminescentColor : result.BioluminescentColor; // Hybrids have a high chance of being seedless. Balances very @@ -171,6 +177,19 @@ public class MutationSystem : EntitySystem val = polarity; } + private void MutateHarvestType(ref HarvestType val, int bits, int totalbits, float mult) + { + float p = mult * bits/totalbits; + if (!random(p)) + return; + + if (val == HarvestType.NoRepeat) + val = HarvestType.Repeat; + + else if (val == HarvestType.Repeat) + val = HarvestType.SelfHarvest; + } + private Color RandomColor(Color color, int bits, int totalbits, float mult) { float p = mult*bits/totalbits; diff --git a/Content.Server/Botany/Systems/PlantHolderSystem.cs b/Content.Server/Botany/Systems/PlantHolderSystem.cs index 6091b98a53..5a5c0fbba2 100644 --- a/Content.Server/Botany/Systems/PlantHolderSystem.cs +++ b/Content.Server/Botany/Systems/PlantHolderSystem.cs @@ -23,6 +23,7 @@ using Robust.Shared.Timing; using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Content.Server.Coordinates.Helpers; namespace Content.Server.Botany.Systems { @@ -32,7 +33,7 @@ namespace Content.Server.Botany.Systems [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly MutationSystem _mutation = default!; [Dependency] private readonly AppearanceSystem _appearance = default!; - [Dependency] private readonly AudioSystem _audio = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly TagSystem _tagSystem = default!; @@ -78,8 +79,8 @@ namespace Content.Server.Botany.Systems { var displayName = Loc.GetString(component.Seed.DisplayName); args.PushMarkup(Loc.GetString("plant-holder-component-something-already-growing-message", - ("seedName", displayName), - ("toBeForm", displayName.EndsWith('s') ? "are" : "is"))); + ("seedName", displayName), + ("toBeForm", displayName.EndsWith('s') ? "are" : "is"))); if (component.Health <= component.Seed.Endurance / 2) { @@ -133,7 +134,7 @@ namespace Content.Server.Botany.Systems if (component.Seed == null) { if (!_botanySystem.TryGetSeed(seeds, out var seed)) - return ; + return; var name = Loc.GetString(seed.Name); var noun = Loc.GetString(seed.Noun); @@ -209,7 +210,7 @@ namespace Content.Server.Botany.Systems _audio.PlayPvs(spray.SpraySound, args.Used, AudioParams.Default.WithVariation(0.125f)); - var split =_solutionSystem.Drain(solutionEntity, solution, amount); + var split = _solutionSystem.Drain(solutionEntity, solution, amount); if (split.Volume == 0) { @@ -222,7 +223,7 @@ namespace Content.Server.Botany.Systems ("owner", uid), ("amount", split.Volume)), args.User, PopupType.Medium); - _solutionSystem.TryAddSolution(targetEntity, targetSolution, split); + _solutionSystem.TryAddSolution(targetEntity, targetSolution, split); ForceUpdateByExternalCause(uid, component); @@ -257,6 +258,11 @@ namespace Content.Server.Botany.Systems ("seedName", displayName)), args.User); component.Health -= (_random.Next(3, 5) * 10); + if (component.Seed != null && component.Seed.CanScream) + { + _audio.PlayPvs(component.Seed.ScreamSound, uid, AudioParams.Default.WithVolume(-2)); + } + if (_random.Prob(0.3f)) component.Sampled = true; @@ -283,8 +289,8 @@ namespace Content.Server.Botany.Systems if (_solutionSystem.TryGetSolution(args.Used, produce.SolutionName, out var solution2)) { // This deliberately discards overfill. - _solutionSystem.TryAddSolution(args.Used, solution2, - _solutionSystem.SplitSolution(args.Used, solution2, solution2.Volume)); + _solutionSystem.TryAddSolution(args.Used, solution2, + _solutionSystem.SplitSolution(args.Used, solution2, solution2.Volume)); ForceUpdateByExternalCause(uid, component); } @@ -303,6 +309,7 @@ namespace Content.Server.Botany.Systems // TODO } + public void Update(EntityUid uid, PlantHolderComponent? component = null) { if (!Resolve(uid, ref component)) @@ -331,14 +338,31 @@ namespace Content.Server.Botany.Systems } // Weeds like water and nutrients! They may appear even if there's not a seed planted. - if (component.WaterLevel > 10 && component.NutritionLevel > 2 && _random.Prob(component.Seed == null ? 0.05f : 0.01f)) + if (component.WaterLevel > 10 && component.NutritionLevel > 2) { - component.WeedLevel += 1 * HydroponicsSpeedMultiplier * component.WeedCoefficient; + var chance = 0f; + if (component.Seed == null) + chance = 0.05f; + else if (component.Seed.TurnIntoKudzu) + chance = 1f; + else + chance = 0.01f; + + if (_random.Prob(chance)) + component.WeedLevel += 1 + HydroponicsSpeedMultiplier * component.WeedCoefficient; if (component.DrawWarnings) component.UpdateSpriteAfterUpdate = true; } + if (component.Seed != null && component.Seed.TurnIntoKudzu + && component.WeedLevel >= component.Seed.WeedHighLevelThreshold) + { + Spawn(component.Seed.KudzuPrototype, Transform(uid).Coordinates.SnapToGrid(EntityManager)); + component.Seed.TurnIntoKudzu = false; + component.Health = 0; + } + // There's a chance for a weed explosion to happen if weeds take over. // Plants that are themselves weeds (WeedTolerance > 8) are unaffected. if (component.WeedLevel >= 10 && _random.Prob(0.1f)) @@ -399,7 +423,7 @@ namespace Content.Server.Botany.Systems if (!component.Seed.Viable) { AffectGrowth(uid, -1, component); - component.Health -= 6*healthMod; + component.Health -= 6 * healthMod; } // Make sure the plant is not starving. @@ -435,6 +459,7 @@ namespace Content.Server.Botany.Systems if (component.DrawWarnings) component.UpdateSpriteAfterUpdate = true; } + var environment = _atmosphere.GetContainingMixture(uid, true, true) ?? GasMixture.SpaceGas; if (component.Seed.ConsumeGasses.Count > 0) @@ -670,6 +695,9 @@ namespace Content.Server.Botany.Systems component.Harvest = false; component.LastProduce = component.Age; + if (component.Seed != null && component.Seed.CanScream) + _audio.PlayPvs(component.Seed.ScreamSound, uid, AudioParams.Default.WithVolume(-2)); + if (component.Seed?.HarvestRepeat == HarvestType.NoRepeat) RemovePlant(uid, component); @@ -832,8 +860,7 @@ namespace Content.Server.Botany.Systems { if (component.DrawWarnings) { - _appearance.SetData(uid, PlantHolderVisuals.HealthLight, - component.Health <= component.Seed.Endurance / 2f); + _appearance.SetData(uid, PlantHolderVisuals.HealthLight, component.Health <= component.Seed.Endurance / 2f); } if (component.Dead) diff --git a/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml b/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml index 4d141dceb5..331056cb08 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/kudzu.yml @@ -78,6 +78,14 @@ walkSpeedModifier: 0.2 sprintSpeedModifier: 0.2 +- type: entity + id: WeakKudzu + parent: Kudzu + components: + - type: Spreader + growthResult: WeakKudzu + chance: 0.3 + - type: entity id: FleshKudzu name: tendons