ECS botany except for plantholder (#6466)
This commit is contained in:
@@ -1,37 +1,19 @@
|
|||||||
using System.Threading.Tasks;
|
using Content.Server.Botany.Systems;
|
||||||
using Content.Shared.ActionBlocker;
|
using Robust.Shared.Analyzers;
|
||||||
using Content.Shared.Interaction;
|
|
||||||
using Content.Shared.Random.Helpers;
|
|
||||||
using Content.Shared.Tag;
|
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Server.Botany.Components
|
namespace Content.Server.Botany.Components;
|
||||||
|
// TODO: This should probably be merged with SliceableFood somehow or made into a more generic Choppable.
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
[Friend(typeof(LogSystem))]
|
||||||
|
public sealed class LogComponent : Component
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[DataField("spawnedPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
public class LogComponent : Component, IInteractUsing
|
public string SpawnedPrototype = "MaterialWoodPlank1";
|
||||||
{
|
|
||||||
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(eventArgs.User))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
[DataField("spawnCount")] public int SpawnCount = 2;
|
||||||
|
|
||||||
if (eventArgs.Using.HasTag("BotanySharp"))
|
|
||||||
{
|
|
||||||
for (var i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
var plank = entMan.SpawnEntity("MaterialWoodPlank1", entMan.GetComponent<TransformComponent>(Owner).Coordinates);
|
|
||||||
plank.RandomOffset(0.25f);
|
|
||||||
}
|
|
||||||
|
|
||||||
entMan.QueueDeleteEntity(Owner);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Atmos;
|
using Content.Server.Atmos;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
|
using Content.Server.Botany.Systems;
|
||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
using Content.Server.Chemistry.Components;
|
using Content.Server.Chemistry.Components;
|
||||||
using Content.Server.Fluids.Components;
|
using Content.Server.Fluids.Components;
|
||||||
@@ -107,7 +108,7 @@ namespace Content.Server.Botany.Components
|
|||||||
public float WeedCoefficient { get; set; } = 1f;
|
public float WeedCoefficient { get; set; } = 1f;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public Seed? Seed { get; set; }
|
public SeedPrototype? Seed { get; set; }
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public bool ImproperHeat { get; set; }
|
public bool ImproperHeat { get; set; }
|
||||||
@@ -146,6 +147,8 @@ namespace Content.Server.Botany.Components
|
|||||||
|
|
||||||
_lastCycle = curTime;
|
_lastCycle = curTime;
|
||||||
|
|
||||||
|
// todo ecs.
|
||||||
|
var botanySystem = EntitySystem.Get<BotanySystem>();
|
||||||
|
|
||||||
// Weeds like water and nutrients! They may appear even if there's not a seed planted.
|
// Weeds like water and nutrients! They may appear even if there's not a seed planted.
|
||||||
if (WaterLevel > 10 && NutritionLevel > 2 && _random.Prob(Seed == null ? 0.05f : 0.01f))
|
if (WaterLevel > 10 && NutritionLevel > 2 && _random.Prob(Seed == null ? 0.05f : 0.01f))
|
||||||
@@ -272,7 +275,7 @@ namespace Content.Server.Botany.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seed pressure resistance.
|
// SeedPrototype pressure resistance.
|
||||||
var pressure = environment.Pressure;
|
var pressure = environment.Pressure;
|
||||||
if (pressure < Seed.LowPressureTolerance || pressure > Seed.HighPressureTolerance)
|
if (pressure < Seed.LowPressureTolerance || pressure > Seed.HighPressureTolerance)
|
||||||
{
|
{
|
||||||
@@ -286,7 +289,7 @@ namespace Content.Server.Botany.Components
|
|||||||
ImproperPressure = false;
|
ImproperPressure = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seed ideal temperature.
|
// SeedPrototype ideal temperature.
|
||||||
if (MathF.Abs(environment.Temperature - Seed.IdealHeat) > Seed.HeatTolerance)
|
if (MathF.Abs(environment.Temperature - Seed.IdealHeat) > Seed.HeatTolerance)
|
||||||
{
|
{
|
||||||
Health -= healthMod;
|
Health -= healthMod;
|
||||||
@@ -359,7 +362,7 @@ namespace Content.Server.Botany.Components
|
|||||||
}
|
}
|
||||||
else if (Age < 0) // Revert back to seed packet!
|
else if (Age < 0) // Revert back to seed packet!
|
||||||
{
|
{
|
||||||
Seed.SpawnSeedPacket(_entMan.GetComponent<TransformComponent>(Owner).Coordinates);
|
botanySystem.SpawnSeedPacket(Seed, _entMan.GetComponent<TransformComponent>(Owner).Coordinates);
|
||||||
RemovePlant();
|
RemovePlant();
|
||||||
ForceUpdate = true;
|
ForceUpdate = true;
|
||||||
Update();
|
Update();
|
||||||
@@ -422,19 +425,21 @@ namespace Content.Server.Botany.Components
|
|||||||
if (Seed == null || _entMan.Deleted(user) || !EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
|
if (Seed == null || _entMan.Deleted(user) || !EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
var botanySystem = EntitySystem.Get<BotanySystem>();
|
||||||
|
|
||||||
if (Harvest && !Dead)
|
if (Harvest && !Dead)
|
||||||
{
|
{
|
||||||
if (_entMan.TryGetComponent(user, out HandsComponent? hands))
|
if (_entMan.TryGetComponent(user, out HandsComponent? hands))
|
||||||
{
|
{
|
||||||
if (!Seed.CheckHarvest(user, hands.GetActiveHandItem?.Owner))
|
if (!botanySystem.CanHarvest(Seed, hands.GetActiveHandItem?.Owner))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!Seed.CheckHarvest(user))
|
else if (!botanySystem.CanHarvest(Seed))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Seed.Harvest(user, YieldMod);
|
botanySystem.Harvest(Seed, user, YieldMod);
|
||||||
AfterHarvest();
|
AfterHarvest();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -451,7 +456,9 @@ namespace Content.Server.Botany.Components
|
|||||||
if (Seed == null || !Harvest)
|
if (Seed == null || !Harvest)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Seed.AutoHarvest(_entMan.GetComponent<TransformComponent>(Owner).Coordinates);
|
var botanySystem = EntitySystem.Get<BotanySystem>();
|
||||||
|
|
||||||
|
botanySystem.AutoHarvest(Seed, _entMan.GetComponent<TransformComponent>(Owner).Coordinates);
|
||||||
AfterHarvest();
|
AfterHarvest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,7 +640,7 @@ namespace Content.Server.Botany.Components
|
|||||||
// If this seed is not in the global seed list, then no products of this line have been harvested yet.
|
// If this seed is not in the global seed list, then no products of this line have been harvested yet.
|
||||||
// It is then safe to assume it's restricted to this tray.
|
// It is then safe to assume it's restricted to this tray.
|
||||||
if (Seed == null) return;
|
if (Seed == null) return;
|
||||||
var plantSystem = EntitySystem.Get<PlantSystem>();
|
var plantSystem = EntitySystem.Get<BotanySystem>();
|
||||||
if (plantSystem.Seeds.ContainsKey(Seed.Uid))
|
if (plantSystem.Seeds.ContainsKey(Seed.Uid))
|
||||||
Seed = Seed.Diverge(modified);
|
Seed = Seed.Diverge(modified);
|
||||||
}
|
}
|
||||||
@@ -653,22 +660,21 @@ namespace Content.Server.Botany.Components
|
|||||||
if ((!_entMan.EntityExists(usingItem) ? EntityLifeStage.Deleted : _entMan.GetComponent<MetaDataComponent>(usingItem).EntityLifeStage) >= EntityLifeStage.Deleted || !EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
|
if ((!_entMan.EntityExists(usingItem) ? EntityLifeStage.Deleted : _entMan.GetComponent<MetaDataComponent>(usingItem).EntityLifeStage) >= EntityLifeStage.Deleted || !EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
var botanySystem = EntitySystem.Get<BotanySystem>();
|
||||||
|
|
||||||
if (_entMan.TryGetComponent(usingItem, out SeedComponent? seeds))
|
if (_entMan.TryGetComponent(usingItem, out SeedComponent? seeds))
|
||||||
{
|
{
|
||||||
if (Seed == null)
|
if (Seed == null)
|
||||||
{
|
{
|
||||||
if (seeds.Seed == null)
|
var protoMan = IoCManager.Resolve<IPrototypeManager>();
|
||||||
{
|
if (!protoMan.TryIndex<SeedPrototype>(seeds.SeedName, out var seed))
|
||||||
user.PopupMessageCursor(Loc.GetString("plant-holder-component-empty-seed-packet-message"));
|
|
||||||
_entMan.QueueDeleteEntity(usingItem);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
user.PopupMessageCursor(Loc.GetString("plant-holder-component-plant-success-message",
|
user.PopupMessageCursor(Loc.GetString("plant-holder-component-plant-success-message",
|
||||||
("seedName", seeds.Seed.SeedName),
|
("seedName", seed.SeedName),
|
||||||
("seedNoun", seeds.Seed.SeedNoun)));
|
("seedNoun", seed.SeedNoun)));
|
||||||
|
|
||||||
Seed = seeds.Seed;
|
Seed = seed;
|
||||||
Dead = false;
|
Dead = false;
|
||||||
Age = 1;
|
Age = 1;
|
||||||
Health = Seed.Endurance;
|
Health = Seed.Endurance;
|
||||||
@@ -778,7 +784,7 @@ namespace Content.Server.Botany.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var seed = Seed.SpawnSeedPacket(_entMan.GetComponent<TransformComponent>(user).Coordinates);
|
var seed = botanySystem.SpawnSeedPacket(Seed, _entMan.GetComponent<TransformComponent>(user).Coordinates);
|
||||||
seed.RandomOffset(0.25f);
|
seed.RandomOffset(0.25f);
|
||||||
user.PopupMessageCursor(Loc.GetString("plant-holder-component-take-sample-message",
|
user.PopupMessageCursor(Loc.GetString("plant-holder-component-take-sample-message",
|
||||||
("seedName", Seed.DisplayName)));
|
("seedName", Seed.DisplayName)));
|
||||||
|
|||||||
@@ -1,62 +1,15 @@
|
|||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Botany.Systems;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Robust.Shared.Analyzers;
|
||||||
using Content.Shared.FixedPoint;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.Botany.Components
|
namespace Content.Server.Botany.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
[Friend(typeof(BotanySystem))]
|
||||||
|
public sealed class ProduceComponent : Component
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[DataField("targetSolution")] public string SolutionName { get; set; } = "food";
|
||||||
public class ProduceComponent : Component, ISerializationHooks
|
|
||||||
{
|
|
||||||
[DataField("targetSolution")] public string SolutionName { get; set; } = "food";
|
|
||||||
|
|
||||||
[DataField("seed")] private string? _seedName;
|
[DataField("seed", required: true)] public string SeedName = default!;
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public Seed? Seed
|
|
||||||
{
|
|
||||||
get => _seedName != null ? IoCManager.Resolve<IPrototypeManager>().Index<Seed>(_seedName) : null;
|
|
||||||
set => _seedName = value?.ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Potency => Seed?.Potency ?? 0;
|
|
||||||
|
|
||||||
public void Grown()
|
|
||||||
{
|
|
||||||
if (Seed == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(Owner, out SpriteComponent? sprite))
|
|
||||||
{
|
|
||||||
sprite.LayerSetRSI(0, Seed.PlantRsi);
|
|
||||||
sprite.LayerSetState(0, Seed.PlantIconState);
|
|
||||||
}
|
|
||||||
|
|
||||||
var solutionContainer = EntitySystem.Get<SolutionContainerSystem>().EnsureSolution(Owner, SolutionName);
|
|
||||||
if (solutionContainer == null)
|
|
||||||
{
|
|
||||||
Logger.Warning($"No solution container found in {nameof(ProduceComponent)}.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
solutionContainer.RemoveAllSolution();
|
|
||||||
foreach (var (chem, quantity) in Seed.Chemicals)
|
|
||||||
{
|
|
||||||
var amount = FixedPoint2.New(quantity.Min);
|
|
||||||
if (quantity.PotencyDivisor > 0 && Potency > 0)
|
|
||||||
amount += FixedPoint2.New(Potency / quantity.PotencyDivisor);
|
|
||||||
amount = FixedPoint2.New((int) MathHelper.Clamp(amount.Float(), quantity.Min, quantity.Max));
|
|
||||||
solutionContainer.MaxVolume += amount;
|
|
||||||
solutionContainer.AddReagent(chem, amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,15 @@
|
|||||||
using Content.Shared.Examine;
|
using Content.Server.Botany.Systems;
|
||||||
|
using Robust.Shared.Analyzers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.Botany.Components
|
namespace Content.Server.Botany.Components
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent, Friend(typeof(BotanySystem))]
|
||||||
#pragma warning disable 618
|
public sealed class SeedComponent : Component
|
||||||
public class SeedComponent : Component, IExamine
|
|
||||||
#pragma warning restore 618
|
|
||||||
{
|
{
|
||||||
[DataField("seed")]
|
[DataField("seed", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<SeedPrototype>))]
|
||||||
private string? _seedName;
|
public string SeedName = default!;
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public Seed? Seed
|
|
||||||
{
|
|
||||||
get => _seedName != null ? IoCManager.Resolve<IPrototypeManager>().Index<Seed>(_seedName) : null;
|
|
||||||
set => _seedName = value?.ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Examine(FormattedMessage message, bool inDetailsRange)
|
|
||||||
{
|
|
||||||
if (!inDetailsRange)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Seed == null)
|
|
||||||
{
|
|
||||||
message.AddMarkup(Loc.GetString("seed-component-no-seeds-message") + "\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.AddMarkup(Loc.GetString($"seed-component-description", ("seedName", Seed.DisplayName)) + "\n");
|
|
||||||
|
|
||||||
if (!Seed.RoundStart)
|
|
||||||
{
|
|
||||||
message.AddMarkup(Loc.GetString($"seed-component-has-variety-tag", ("seedUid", Seed.Uid)) + "\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
message.AddMarkup(Loc.GetString($"seed-component-plant-yield-text", ("seedYield", Seed.Yield)) + "\n");
|
|
||||||
message.AddMarkup(Loc.GetString($"seed-component-plant-potency-text", ("seedPotency", Seed.Potency)) + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,16 @@
|
|||||||
using System.Threading.Tasks;
|
using Content.Server.Botany.Systems;
|
||||||
using Content.Server.Power.Components;
|
using Robust.Shared.Analyzers;
|
||||||
using Content.Shared.Interaction;
|
|
||||||
using Content.Shared.Popups;
|
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
|
|
||||||
namespace Content.Server.Botany.Components
|
namespace Content.Server.Botany.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
[Friend(typeof(SeedExtractorSystem))]
|
||||||
|
public sealed class SeedExtractorComponent : Component
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
// TODO: Upgradeable machines.
|
||||||
public class SeedExtractorComponent : Component, IInteractUsing
|
[DataField("minSeeds")] public int MinSeeds = 1;
|
||||||
{
|
|
||||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
|
||||||
|
|
||||||
// TODO: Upgradeable machines.
|
[DataField("maxSeeds")] public int MaxSeeds = 4;
|
||||||
private int _minSeeds = 1;
|
|
||||||
private int _maxSeeds = 4;
|
|
||||||
|
|
||||||
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (!_entMan.TryGetComponent<ApcPowerReceiverComponent>(Owner, out var powerReceiverComponent) || !powerReceiverComponent.Powered)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (_entMan.TryGetComponent(eventArgs.Using, out ProduceComponent? produce) && produce.Seed != null)
|
|
||||||
{
|
|
||||||
eventArgs.User.PopupMessageCursor(Loc.GetString("seed-extractor-component-interact-message",("name", _entMan.GetComponent<MetaDataComponent>(eventArgs.Using).EntityName)));
|
|
||||||
|
|
||||||
_entMan.QueueDeleteEntity(eventArgs.Using);
|
|
||||||
|
|
||||||
var random = _random.Next(_minSeeds, _maxSeeds);
|
|
||||||
|
|
||||||
for (var i = 0; i < random; i++)
|
|
||||||
{
|
|
||||||
produce.Seed.SpawnSeedPacket(_entMan.GetComponent<TransformComponent>(Owner).Coordinates, _entMan);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,362 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Content.Server.Botany.Components;
|
|
||||||
using Content.Server.Plants;
|
|
||||||
using Content.Shared.Atmos;
|
|
||||||
using Content.Shared.Popups;
|
|
||||||
using Content.Shared.Random.Helpers;
|
|
||||||
using Content.Shared.Tag;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.Botany
|
|
||||||
{
|
|
||||||
public enum HarvestType : byte
|
|
||||||
{
|
|
||||||
NoRepeat,
|
|
||||||
Repeat,
|
|
||||||
SelfHarvest,
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public enum PlantSpread : byte
|
|
||||||
{
|
|
||||||
NoSpread,
|
|
||||||
Creepers,
|
|
||||||
Vines,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PlantMutation : byte
|
|
||||||
{
|
|
||||||
NoMutation,
|
|
||||||
Mutable,
|
|
||||||
HighlyMutable,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PlantCarnivorous : byte
|
|
||||||
{
|
|
||||||
NotCarnivorous,
|
|
||||||
EatPests,
|
|
||||||
EatLivingBeings,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PlantJuicy : byte
|
|
||||||
{
|
|
||||||
NotJuicy,
|
|
||||||
Juicy,
|
|
||||||
Slippery,
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
[DataDefinition]
|
|
||||||
public struct SeedChemQuantity
|
|
||||||
{
|
|
||||||
[DataField("Min")]
|
|
||||||
public int Min;
|
|
||||||
[DataField("Max")]
|
|
||||||
public int Max;
|
|
||||||
[DataField("PotencyDivisor")]
|
|
||||||
public int PotencyDivisor;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Prototype("seed")]
|
|
||||||
public class Seed : IPrototype
|
|
||||||
{
|
|
||||||
private const string SeedPrototype = "SeedBase";
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("id", required: true)]
|
|
||||||
public string ID { get; private init; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unique identifier of this seed. Do NOT set this.
|
|
||||||
/// </summary>
|
|
||||||
public int Uid { get; internal set; } = -1;
|
|
||||||
|
|
||||||
#region Tracking
|
|
||||||
|
|
||||||
[ViewVariables] [DataField("name")] public string Name { get; set; } = string.Empty;
|
|
||||||
[ViewVariables] [DataField("seedName")] public string SeedName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("seedNoun")]
|
|
||||||
public string SeedNoun { get; set; } = "seeds";
|
|
||||||
[ViewVariables] [DataField("displayName")] public string DisplayName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("roundStart")]
|
|
||||||
public bool RoundStart { get; private set; } = true;
|
|
||||||
[ViewVariables] [DataField("mysterious")] public bool Mysterious { get; set; }
|
|
||||||
[ViewVariables] [DataField("immutable")] public bool Immutable { get; set; }
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Output
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("productPrototypes", customTypeSerializer:typeof(PrototypeIdListSerializer<EntityPrototype>))]
|
|
||||||
public List<string> ProductPrototypes { get; set; } = new();
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("chemicals")]
|
|
||||||
public Dictionary<string, SeedChemQuantity> Chemicals { get; set; } = new();
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("consumeGasses")]
|
|
||||||
public Dictionary<Gas, float> ConsumeGasses { get; set; } = new();
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("exudeGasses")]
|
|
||||||
public Dictionary<Gas, float> ExudeGasses { get; set; } = new();
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Tolerances
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("nutrientConsumption")]
|
|
||||||
public float NutrientConsumption { get; set; } = 0.25f;
|
|
||||||
|
|
||||||
[ViewVariables] [DataField("waterConsumption")] public float WaterConsumption { get; set; } = 3f;
|
|
||||||
[ViewVariables] [DataField("idealHeat")] public float IdealHeat { get; set; } = 293f;
|
|
||||||
[ViewVariables] [DataField("heatTolerance")] public float HeatTolerance { get; set; } = 20f;
|
|
||||||
[ViewVariables] [DataField("idealLight")] public float IdealLight { get; set; } = 7f;
|
|
||||||
[ViewVariables] [DataField("lightTolerance")] public float LightTolerance { get; set; } = 5f;
|
|
||||||
[ViewVariables] [DataField("toxinsTolerance")] public float ToxinsTolerance { get; set; } = 4f;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("lowPressureTolerance")]
|
|
||||||
public float LowPressureTolerance { get; set; } = 25f;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("highPressureTolerance")]
|
|
||||||
public float HighPressureTolerance { get; set; } = 200f;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("pestTolerance")]
|
|
||||||
public float PestTolerance { get; set; } = 5f;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("weedTolerance")]
|
|
||||||
public float WeedTolerance { get; set; } = 5f;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region General traits
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("endurance")]
|
|
||||||
public float Endurance { get; set; } = 100f;
|
|
||||||
[ViewVariables] [DataField("yield")] public int Yield { get; set; }
|
|
||||||
[ViewVariables] [DataField("lifespan")] public float Lifespan { get; set; }
|
|
||||||
[ViewVariables] [DataField("maturation")] public float Maturation { get; set; }
|
|
||||||
[ViewVariables] [DataField("production")] public float Production { get; set; }
|
|
||||||
[ViewVariables] [DataField("growthStages")] public int GrowthStages { get; set; } = 6;
|
|
||||||
[ViewVariables] [DataField("harvestRepeat")] public HarvestType HarvestRepeat { get; set; } = HarvestType.NoRepeat;
|
|
||||||
|
|
||||||
[ViewVariables] [DataField("potency")] public float Potency { get; set; } = 1f;
|
|
||||||
// No, I'm not removing these.
|
|
||||||
//public PlantSpread Spread { get; set; }
|
|
||||||
//public PlantMutation Mutation { get; set; }
|
|
||||||
//public float AlterTemperature { get; set; }
|
|
||||||
//public PlantCarnivorous Carnivorous { get; set; }
|
|
||||||
//public bool Parasite { get; set; }
|
|
||||||
//public bool Hematophage { get; set; }
|
|
||||||
//public bool Thorny { get; set; }
|
|
||||||
//public bool Stinging { get; set; }
|
|
||||||
[DataField("ligneous")]
|
|
||||||
public bool Ligneous { get; set; }
|
|
||||||
// public bool Teleporting { get; set; }
|
|
||||||
// public PlantJuicy Juicy { get; set; }
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Cosmetics
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("plantRsi", required: true)]
|
|
||||||
public ResourcePath PlantRsi { get; set; } = default!;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("plantIconState")]
|
|
||||||
public string PlantIconState { get; set; } = "produce";
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("bioluminescent")]
|
|
||||||
public bool Bioluminescent { get; set; }
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("bioluminescentColor")]
|
|
||||||
public Color BioluminescentColor { get; set; } = Color.White;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("splatPrototype")]
|
|
||||||
public string? SplatPrototype { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public Seed Clone()
|
|
||||||
{
|
|
||||||
var newSeed = new Seed()
|
|
||||||
{
|
|
||||||
ID = ID,
|
|
||||||
Name = Name,
|
|
||||||
SeedName = SeedName,
|
|
||||||
SeedNoun = SeedNoun,
|
|
||||||
RoundStart = RoundStart,
|
|
||||||
Mysterious = Mysterious,
|
|
||||||
|
|
||||||
ProductPrototypes = new List<string>(ProductPrototypes),
|
|
||||||
Chemicals = new Dictionary<string, SeedChemQuantity>(Chemicals),
|
|
||||||
ConsumeGasses = new Dictionary<Gas, float>(ConsumeGasses),
|
|
||||||
ExudeGasses = new Dictionary<Gas, float>(ExudeGasses),
|
|
||||||
|
|
||||||
NutrientConsumption = NutrientConsumption,
|
|
||||||
WaterConsumption = WaterConsumption,
|
|
||||||
IdealHeat = IdealHeat,
|
|
||||||
HeatTolerance = HeatTolerance,
|
|
||||||
IdealLight = IdealLight,
|
|
||||||
LightTolerance = LightTolerance,
|
|
||||||
ToxinsTolerance = ToxinsTolerance,
|
|
||||||
LowPressureTolerance = LowPressureTolerance,
|
|
||||||
HighPressureTolerance = HighPressureTolerance,
|
|
||||||
PestTolerance = PestTolerance,
|
|
||||||
WeedTolerance = WeedTolerance,
|
|
||||||
|
|
||||||
Endurance = Endurance,
|
|
||||||
Yield = Yield,
|
|
||||||
Lifespan = Lifespan,
|
|
||||||
Maturation = Maturation,
|
|
||||||
Production = Production,
|
|
||||||
GrowthStages = GrowthStages,
|
|
||||||
HarvestRepeat = HarvestRepeat,
|
|
||||||
Potency = Potency,
|
|
||||||
|
|
||||||
PlantRsi = PlantRsi,
|
|
||||||
PlantIconState = PlantIconState,
|
|
||||||
Bioluminescent = Bioluminescent,
|
|
||||||
BioluminescentColor = BioluminescentColor,
|
|
||||||
SplatPrototype = SplatPrototype,
|
|
||||||
};
|
|
||||||
|
|
||||||
return newSeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityUid SpawnSeedPacket(EntityCoordinates transformCoordinates, IEntityManager? entityManager = null)
|
|
||||||
{
|
|
||||||
entityManager ??= IoCManager.Resolve<IEntityManager>();
|
|
||||||
|
|
||||||
var seed = entityManager.SpawnEntity(SeedPrototype, transformCoordinates);
|
|
||||||
|
|
||||||
var seedComp = seed.EnsureComponent<SeedComponent>();
|
|
||||||
seedComp.Seed = this;
|
|
||||||
|
|
||||||
if (entityManager.TryGetComponent(seed, out SpriteComponent? sprite))
|
|
||||||
{
|
|
||||||
// Seed state will always be seed. Blame the spriter if that's not the case!
|
|
||||||
sprite.LayerSetSprite(0, new SpriteSpecifier.Rsi(PlantRsi, "seed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
string val = Loc.GetString("botany-seed-packet-name", ("seedName", SeedName), ("seedNoun", SeedNoun));
|
|
||||||
entityManager.GetComponent<MetaDataComponent>(seed).EntityName = val;
|
|
||||||
|
|
||||||
return seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddToDatabase()
|
|
||||||
{
|
|
||||||
var plantSystem = EntitySystem.Get<PlantSystem>();
|
|
||||||
if (plantSystem.AddSeedToDatabase(this))
|
|
||||||
{
|
|
||||||
Name = Uid.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<EntityUid> AutoHarvest(EntityCoordinates position, int yieldMod = 1)
|
|
||||||
{
|
|
||||||
if (position.IsValid(IoCManager.Resolve<IEntityManager>()) && ProductPrototypes != null &&
|
|
||||||
ProductPrototypes.Count > 0)
|
|
||||||
return GenerateProduct(position, yieldMod);
|
|
||||||
|
|
||||||
return Enumerable.Empty<EntityUid>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<EntityUid> Harvest(EntityUid user, int yieldMod = 1)
|
|
||||||
{
|
|
||||||
AddToDatabase();
|
|
||||||
|
|
||||||
if (ProductPrototypes == null || ProductPrototypes.Count == 0 || Yield <= 0)
|
|
||||||
{
|
|
||||||
user.PopupMessageCursor(Loc.GetString("botany-harvest-fail-message"));
|
|
||||||
return Enumerable.Empty<EntityUid>();
|
|
||||||
}
|
|
||||||
|
|
||||||
user.PopupMessageCursor(Loc.GetString("botany-harvest-success-message", ("name", DisplayName)));
|
|
||||||
return GenerateProduct(IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(user).Coordinates, yieldMod);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<EntityUid> GenerateProduct(EntityCoordinates position, int yieldMod = 1)
|
|
||||||
{
|
|
||||||
var totalYield = 0;
|
|
||||||
if (Yield > -1)
|
|
||||||
{
|
|
||||||
if (yieldMod < 0)
|
|
||||||
{
|
|
||||||
yieldMod = 1;
|
|
||||||
totalYield = Yield;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
totalYield = Yield * yieldMod;
|
|
||||||
}
|
|
||||||
|
|
||||||
totalYield = Math.Max(1, totalYield);
|
|
||||||
}
|
|
||||||
|
|
||||||
var random = IoCManager.Resolve<IRobustRandom>();
|
|
||||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
|
||||||
|
|
||||||
var products = new List<EntityUid>();
|
|
||||||
|
|
||||||
for (var i = 0; i < totalYield; i++)
|
|
||||||
{
|
|
||||||
var product = random.Pick(ProductPrototypes);
|
|
||||||
|
|
||||||
var entity = entityManager.SpawnEntity(product, position);
|
|
||||||
entity.RandomOffset(0.25f);
|
|
||||||
products.Add(entity);
|
|
||||||
|
|
||||||
var produce = entity.EnsureComponent<ProduceComponent>();
|
|
||||||
|
|
||||||
produce.Seed = this;
|
|
||||||
produce.Grown();
|
|
||||||
|
|
||||||
if (Mysterious)
|
|
||||||
{
|
|
||||||
var metaData = entityManager.GetComponent<MetaDataComponent>(entity);
|
|
||||||
metaData.EntityName += "?";
|
|
||||||
metaData.EntityDescription += (" " + Loc.GetString("botany-mysterious-description-addon"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return products;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Seed Diverge(bool modified)
|
|
||||||
{
|
|
||||||
return Clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CheckHarvest(EntityUid user, EntityUid? held = null)
|
|
||||||
{
|
|
||||||
return !Ligneous || (Ligneous && held != null && held.Value.HasTag("BotanySharp"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
222
Content.Server/Botany/SeedPrototype.cs
Normal file
222
Content.Server/Botany/SeedPrototype.cs
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Server.Botany.Components;
|
||||||
|
using Content.Server.Botany.Systems;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Random.Helpers;
|
||||||
|
using Content.Shared.Tag;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Server.Botany;
|
||||||
|
|
||||||
|
public enum HarvestType : byte
|
||||||
|
{
|
||||||
|
NoRepeat,
|
||||||
|
Repeat,
|
||||||
|
SelfHarvest
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public enum PlantSpread : byte
|
||||||
|
{
|
||||||
|
NoSpread,
|
||||||
|
Creepers,
|
||||||
|
Vines,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PlantMutation : byte
|
||||||
|
{
|
||||||
|
NoMutation,
|
||||||
|
Mutable,
|
||||||
|
HighlyMutable,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PlantCarnivorous : byte
|
||||||
|
{
|
||||||
|
NotCarnivorous,
|
||||||
|
EatPests,
|
||||||
|
EatLivingBeings,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PlantJuicy : byte
|
||||||
|
{
|
||||||
|
NotJuicy,
|
||||||
|
Juicy,
|
||||||
|
Slippery,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
[DataDefinition]
|
||||||
|
public struct SeedChemQuantity
|
||||||
|
{
|
||||||
|
[DataField("Min")] public int Min;
|
||||||
|
[DataField("Max")] public int Max;
|
||||||
|
[DataField("PotencyDivisor")] public int PotencyDivisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Prototype("seed")]
|
||||||
|
public sealed class SeedPrototype : IPrototype
|
||||||
|
{
|
||||||
|
public const string Prototype = "SeedBase";
|
||||||
|
|
||||||
|
[DataField("id", required: true)] public string ID { get; private init; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unique identifier of this seed. Do NOT set this.
|
||||||
|
/// </summary>
|
||||||
|
public int Uid { get; internal set; } = -1;
|
||||||
|
|
||||||
|
#region Tracking
|
||||||
|
|
||||||
|
[DataField("name")] public string Name = string.Empty;
|
||||||
|
[DataField("seedName")] public string SeedName = string.Empty;
|
||||||
|
[DataField("seedNoun")] public string SeedNoun = "seeds";
|
||||||
|
[DataField("displayName")] public string DisplayName = string.Empty;
|
||||||
|
|
||||||
|
[DataField("roundStart")] public bool RoundStart = true;
|
||||||
|
[DataField("mysterious")] public bool Mysterious;
|
||||||
|
[DataField("immutable")] public bool Immutable;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Output
|
||||||
|
|
||||||
|
[DataField("productPrototypes", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))]
|
||||||
|
public List<string> ProductPrototypes = new();
|
||||||
|
|
||||||
|
[DataField("chemicals")] public Dictionary<string, SeedChemQuantity> Chemicals = new();
|
||||||
|
|
||||||
|
[DataField("consumeGasses")] public Dictionary<Gas, float> ConsumeGasses = new();
|
||||||
|
|
||||||
|
[DataField("exudeGasses")] public Dictionary<Gas, float> ExudeGasses = new();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Tolerances
|
||||||
|
|
||||||
|
[DataField("nutrientConsumption")] public float NutrientConsumption = 0.25f;
|
||||||
|
|
||||||
|
[DataField("waterConsumption")] public float WaterConsumption = 3f;
|
||||||
|
[DataField("idealHeat")] public float IdealHeat = 293f;
|
||||||
|
[DataField("heatTolerance")] public float HeatTolerance = 20f;
|
||||||
|
[DataField("idealLight")] public float IdealLight = 7f;
|
||||||
|
[DataField("lightTolerance")] public float LightTolerance = 5f;
|
||||||
|
[DataField("toxinsTolerance")] public float ToxinsTolerance = 4f;
|
||||||
|
|
||||||
|
[DataField("lowPressureTolerance")] public float LowPressureTolerance = 25f;
|
||||||
|
|
||||||
|
[DataField("highPressureTolerance")] public float HighPressureTolerance = 200f;
|
||||||
|
|
||||||
|
[DataField("pestTolerance")] public float PestTolerance = 5f;
|
||||||
|
|
||||||
|
[DataField("weedTolerance")] public float WeedTolerance = 5f;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region General traits
|
||||||
|
|
||||||
|
[DataField("endurance")] public float Endurance = 100f;
|
||||||
|
|
||||||
|
[DataField("yield")] public int Yield;
|
||||||
|
[DataField("lifespan")] public float Lifespan;
|
||||||
|
[DataField("maturation")] public float Maturation;
|
||||||
|
[DataField("production")] public float Production;
|
||||||
|
[DataField("growthStages")] public int GrowthStages = 6;
|
||||||
|
[DataField("harvestRepeat")] public HarvestType HarvestRepeat = HarvestType.NoRepeat;
|
||||||
|
|
||||||
|
[DataField("potency")] public float Potency = 1f;
|
||||||
|
|
||||||
|
// No, I'm not removing these.
|
||||||
|
//public PlantSpread Spread { get; set; }
|
||||||
|
//public PlantMutation Mutation { get; set; }
|
||||||
|
//public float AlterTemperature { get; set; }
|
||||||
|
//public PlantCarnivorous Carnivorous { get; set; }
|
||||||
|
//public bool Parasite { get; set; }
|
||||||
|
//public bool Hematophage { get; set; }
|
||||||
|
//public bool Thorny { get; set; }
|
||||||
|
//public bool Stinging { get; set; }
|
||||||
|
|
||||||
|
[DataField("ligneous")] public bool Ligneous;
|
||||||
|
// public bool Teleporting { get; set; }
|
||||||
|
// public PlantJuicy Juicy { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Cosmetics
|
||||||
|
|
||||||
|
[DataField("plantRsi", required: true)]
|
||||||
|
public ResourcePath PlantRsi { get; set; } = default!;
|
||||||
|
|
||||||
|
[DataField("plantIconState")] public string PlantIconState { get; set; } = "produce";
|
||||||
|
|
||||||
|
[DataField("bioluminescent")] public bool Bioluminescent { get; set; }
|
||||||
|
|
||||||
|
[DataField("bioluminescentColor")] public Color BioluminescentColor { get; set; } = Color.White;
|
||||||
|
|
||||||
|
[DataField("splatPrototype")] public string? SplatPrototype { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public SeedPrototype Clone()
|
||||||
|
{
|
||||||
|
var newSeed = new SeedPrototype
|
||||||
|
{
|
||||||
|
ID = ID,
|
||||||
|
Name = Name,
|
||||||
|
SeedName = SeedName,
|
||||||
|
SeedNoun = SeedNoun,
|
||||||
|
RoundStart = RoundStart,
|
||||||
|
Mysterious = Mysterious,
|
||||||
|
|
||||||
|
ProductPrototypes = new List<string>(ProductPrototypes),
|
||||||
|
Chemicals = new Dictionary<string, SeedChemQuantity>(Chemicals),
|
||||||
|
ConsumeGasses = new Dictionary<Gas, float>(ConsumeGasses),
|
||||||
|
ExudeGasses = new Dictionary<Gas, float>(ExudeGasses),
|
||||||
|
|
||||||
|
NutrientConsumption = NutrientConsumption,
|
||||||
|
WaterConsumption = WaterConsumption,
|
||||||
|
IdealHeat = IdealHeat,
|
||||||
|
HeatTolerance = HeatTolerance,
|
||||||
|
IdealLight = IdealLight,
|
||||||
|
LightTolerance = LightTolerance,
|
||||||
|
ToxinsTolerance = ToxinsTolerance,
|
||||||
|
LowPressureTolerance = LowPressureTolerance,
|
||||||
|
HighPressureTolerance = HighPressureTolerance,
|
||||||
|
PestTolerance = PestTolerance,
|
||||||
|
WeedTolerance = WeedTolerance,
|
||||||
|
|
||||||
|
Endurance = Endurance,
|
||||||
|
Yield = Yield,
|
||||||
|
Lifespan = Lifespan,
|
||||||
|
Maturation = Maturation,
|
||||||
|
Production = Production,
|
||||||
|
GrowthStages = GrowthStages,
|
||||||
|
HarvestRepeat = HarvestRepeat,
|
||||||
|
Potency = Potency,
|
||||||
|
|
||||||
|
PlantRsi = PlantRsi,
|
||||||
|
PlantIconState = PlantIconState,
|
||||||
|
Bioluminescent = Bioluminescent,
|
||||||
|
BioluminescentColor = BioluminescentColor,
|
||||||
|
SplatPrototype = SplatPrototype
|
||||||
|
};
|
||||||
|
|
||||||
|
return newSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SeedPrototype Diverge(bool modified)
|
||||||
|
{
|
||||||
|
return Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +1,28 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.Botany;
|
|
||||||
using Content.Server.Botany.Components;
|
using Content.Server.Botany.Components;
|
||||||
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
|
using Content.Server.Popups;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Server.Plants
|
namespace Content.Server.Botany.Systems
|
||||||
{
|
{
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class PlantSystem : EntitySystem
|
public sealed partial class BotanySystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||||
|
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||||
|
|
||||||
private int _nextUid = 0;
|
private int _nextUid = 0;
|
||||||
private readonly Dictionary<int, Seed> _seeds = new();
|
|
||||||
|
|
||||||
private float _timer = 0f;
|
private float _timer = 0f;
|
||||||
|
|
||||||
public IReadOnlyDictionary<int, Seed> Seeds => _seeds;
|
public readonly Dictionary<int, SeedPrototype> Seeds = new();
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -27,6 +30,8 @@ namespace Content.Server.Plants
|
|||||||
|
|
||||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
||||||
|
|
||||||
|
InitializeSeeds();
|
||||||
|
|
||||||
PopulateDatabase();
|
PopulateDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,22 +39,22 @@ namespace Content.Server.Plants
|
|||||||
{
|
{
|
||||||
_nextUid = 0;
|
_nextUid = 0;
|
||||||
|
|
||||||
_seeds.Clear();
|
Seeds.Clear();
|
||||||
|
|
||||||
foreach (var seed in _prototypeManager.EnumeratePrototypes<Seed>())
|
foreach (var seed in _prototypeManager.EnumeratePrototypes<SeedPrototype>())
|
||||||
{
|
{
|
||||||
AddSeedToDatabase(seed);
|
AddSeedToDatabase(seed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AddSeedToDatabase(Seed seed)
|
public bool AddSeedToDatabase(SeedPrototype seed)
|
||||||
{
|
{
|
||||||
// If it's not -1, it's already in the database. Probably.
|
// If it's not -1, it's already in the database. Probably.
|
||||||
if (seed.Uid != -1)
|
if (seed.Uid != -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
seed.Uid = GetNextSeedUid();
|
seed.Uid = GetNextSeedUid();
|
||||||
_seeds[seed.Uid] = seed;
|
Seeds[seed.Uid] = seed;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
35
Content.Server/Botany/Systems/BotanySystem.Produce.cs
Normal file
35
Content.Server/Botany/Systems/BotanySystem.Produce.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Content.Server.Botany.Components;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
|
||||||
|
namespace Content.Server.Botany.Systems;
|
||||||
|
|
||||||
|
public partial class BotanySystem
|
||||||
|
{
|
||||||
|
public void ProduceGrown(EntityUid uid, ProduceComponent produce)
|
||||||
|
{
|
||||||
|
if (!_prototypeManager.TryIndex<SeedPrototype>(produce.SeedName, out var seed))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (TryComp(uid, out SpriteComponent? sprite))
|
||||||
|
{
|
||||||
|
sprite.LayerSetRSI(0, seed.PlantRsi);
|
||||||
|
sprite.LayerSetState(0, seed.PlantIconState);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
solutionContainer.MaxVolume += amount;
|
||||||
|
solutionContainer.AddReagent(chem, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
143
Content.Server/Botany/Systems/BotanySystem.Seed.cs
Normal file
143
Content.Server/Botany/Systems/BotanySystem.Seed.cs
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Server.Botany.Components;
|
||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Random.Helpers;
|
||||||
|
using Content.Shared.Tag;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Server.Botany.Systems;
|
||||||
|
|
||||||
|
public partial class BotanySystem
|
||||||
|
{
|
||||||
|
public void InitializeSeeds()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<SeedComponent, ExaminedEvent>(OnExamined);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnExamined(EntityUid uid, SeedComponent component, ExaminedEvent args)
|
||||||
|
{
|
||||||
|
if (!args.IsInDetailsRange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_prototypeManager.TryIndex<SeedPrototype>(component.SeedName, out var seed))
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.PushMarkup(Loc.GetString($"seed-component-description", ("seedName", seed.DisplayName)));
|
||||||
|
|
||||||
|
if (!seed.RoundStart)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString($"seed-component-has-variety-tag", ("seedUid", seed.Uid)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString($"seed-component-plant-yield-text", ("seedYield", seed.Yield)));
|
||||||
|
args.PushMarkup(Loc.GetString($"seed-component-plant-potency-text", ("seedPotency", seed.Potency)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region SeedPrototype prototype stuff
|
||||||
|
|
||||||
|
public EntityUid SpawnSeedPacket(SeedPrototype proto, EntityCoordinates transformCoordinates)
|
||||||
|
{
|
||||||
|
var seed = Spawn(SeedPrototype.Prototype, transformCoordinates);
|
||||||
|
|
||||||
|
var seedComp = EnsureComp<SeedComponent>(seed);
|
||||||
|
seedComp.SeedName = proto.ID;
|
||||||
|
|
||||||
|
if (TryComp(seed, out SpriteComponent? sprite))
|
||||||
|
{
|
||||||
|
// TODO visualizer
|
||||||
|
// SeedPrototype state will always be seed. Blame the spriter if that's not the case!
|
||||||
|
sprite.LayerSetSprite(0, new SpriteSpecifier.Rsi(proto.PlantRsi, "seed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
string val = Loc.GetString("botany-seed-packet-name", ("seedName", proto.SeedName), ("seedNoun", proto.SeedNoun));
|
||||||
|
MetaData(seed).EntityName = val;
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<EntityUid> AutoHarvest(SeedPrototype proto, EntityCoordinates position, int yieldMod = 1)
|
||||||
|
{
|
||||||
|
if (position.IsValid(EntityManager) &&
|
||||||
|
proto.ProductPrototypes.Count > 0)
|
||||||
|
return GenerateProduct(proto, position, yieldMod);
|
||||||
|
|
||||||
|
return Enumerable.Empty<EntityUid>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<EntityUid> Harvest(SeedPrototype proto, EntityUid user, int yieldMod = 1)
|
||||||
|
{
|
||||||
|
if (AddSeedToDatabase(proto)) proto.Name = proto.Uid.ToString();
|
||||||
|
|
||||||
|
if (proto.ProductPrototypes.Count == 0 || proto.Yield <= 0)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupCursor(Loc.GetString("botany-harvest-fail-message"),
|
||||||
|
Filter.Entities(user));
|
||||||
|
return Enumerable.Empty<EntityUid>();
|
||||||
|
}
|
||||||
|
|
||||||
|
_popupSystem.PopupCursor(Loc.GetString("botany-harvest-success-message", ("name", proto.DisplayName)),
|
||||||
|
Filter.Entities(user));
|
||||||
|
return GenerateProduct(proto, Transform(user).Coordinates, yieldMod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<EntityUid> GenerateProduct(SeedPrototype proto, EntityCoordinates position, int yieldMod = 1)
|
||||||
|
{
|
||||||
|
var totalYield = 0;
|
||||||
|
if (proto.Yield > -1)
|
||||||
|
{
|
||||||
|
if (yieldMod < 0)
|
||||||
|
{
|
||||||
|
yieldMod = 1;
|
||||||
|
totalYield = proto.Yield;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
totalYield = proto.Yield * yieldMod;
|
||||||
|
|
||||||
|
totalYield = Math.Max(1, totalYield);
|
||||||
|
}
|
||||||
|
|
||||||
|
var products = new List<EntityUid>();
|
||||||
|
|
||||||
|
for (var i = 0; i < totalYield; i++)
|
||||||
|
{
|
||||||
|
var product = _robustRandom.Pick(proto.ProductPrototypes);
|
||||||
|
|
||||||
|
var entity = Spawn(product, position);
|
||||||
|
entity.RandomOffset(0.25f);
|
||||||
|
products.Add(entity);
|
||||||
|
|
||||||
|
var produce = EnsureComp<ProduceComponent>(entity);
|
||||||
|
|
||||||
|
produce.SeedName = proto.ID;
|
||||||
|
ProduceGrown(entity, produce);
|
||||||
|
|
||||||
|
if (proto.Mysterious)
|
||||||
|
{
|
||||||
|
var metaData = MetaData(entity);
|
||||||
|
metaData.EntityName += "?";
|
||||||
|
metaData.EntityDescription += " " + Loc.GetString("botany-mysterious-description-addon");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return products;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanHarvest(SeedPrototype proto, EntityUid? held = null)
|
||||||
|
{
|
||||||
|
return !proto.Ligneous || proto.Ligneous && held != null && held.Value.HasTag("BotanySharp");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
32
Content.Server/Botany/Systems/LogSystem.cs
Normal file
32
Content.Server/Botany/Systems/LogSystem.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using Content.Server.Botany.Components;
|
||||||
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Random.Helpers;
|
||||||
|
using Content.Shared.Tag;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.Botany.Systems;
|
||||||
|
|
||||||
|
public sealed class LogSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<LogComponent, InteractUsingEvent>(OnInteractUsing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInteractUsing(EntityUid uid, LogComponent component, InteractUsingEvent args)
|
||||||
|
{
|
||||||
|
if (args.Used.HasTag("BotanySharp"))
|
||||||
|
{
|
||||||
|
for (var i = 0; i < component.SpawnCount; i++)
|
||||||
|
{
|
||||||
|
var plank = Spawn(component.SpawnedPrototype, Transform(uid).Coordinates);
|
||||||
|
plank.RandomOffset(0.25f);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueDel(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
Content.Server/Botany/Systems/SeedExtractorSystem.cs
Normal file
52
Content.Server/Botany/Systems/SeedExtractorSystem.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using Content.Server.Botany.Components;
|
||||||
|
using Content.Server.Popups;
|
||||||
|
using Content.Server.Power.Components;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
|
namespace Content.Server.Botany.Systems;
|
||||||
|
|
||||||
|
public sealed class SeedExtractorSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly BotanySystem _botanySystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SeedExtractorComponent, InteractUsingEvent>(OnInteractUsing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInteractUsing(EntityUid uid, SeedExtractorComponent component, InteractUsingEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<ApcPowerReceiverComponent>(uid, out var powerReceiverComponent) || !powerReceiverComponent.Powered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (TryComp(args.Used, out ProduceComponent? produce))
|
||||||
|
{
|
||||||
|
if (!_prototypeManager.TryIndex<SeedPrototype>(produce.SeedName, out var seed))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_popupSystem.PopupCursor(Loc.GetString("seed-extractor-component-interact-message",("name", args.Used)),
|
||||||
|
Filter.Entities(args.User));
|
||||||
|
|
||||||
|
QueueDel(args.Used);
|
||||||
|
|
||||||
|
var random = _random.Next(component.MinSeeds, component.MaxSeeds);
|
||||||
|
var coords = Transform(uid).Coordinates;
|
||||||
|
|
||||||
|
for (var i = 0; i < random; i++)
|
||||||
|
{
|
||||||
|
_botanySystem.SpawnSeedPacket(seed, coords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
## Entity
|
## Entity
|
||||||
|
|
||||||
plant-holder-component-empty-seed-packet-message = The packet seems to be empty. You throw it away.
|
|
||||||
plant-holder-component-plant-success-message = You plant the {$seedName} {$seedNoun}.
|
plant-holder-component-plant-success-message = You plant the {$seedName} {$seedNoun}.
|
||||||
plant-holder-component-already-seeded-message = The {$name} already has seeds in it!
|
plant-holder-component-already-seeded-message = The {$name} already has seeds in it!
|
||||||
plant-holder-component-remove-weeds-message = You remove the weeds from the {$name}.
|
plant-holder-component-remove-weeds-message = You remove the weeds from the {$name}.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
## Entity
|
## Entity
|
||||||
|
|
||||||
seed-component-no-seeds-message = It doesn't seem to contain any seeds.
|
|
||||||
seed-component-description = It has a picture of [color=yellow]{$seedName}[/color] on the front.
|
seed-component-description = It has a picture of [color=yellow]{$seedName}[/color] on the front.
|
||||||
seed-component-has-variety-tag = It's tagged as variety [color=lightgray]no. {$seedUid}[/color].
|
seed-component-has-variety-tag = It's tagged as variety [color=lightgray]no. {$seedUid}[/color].
|
||||||
seed-component-plant-yield-text = Plant Yield: [color=lightblue]{$seedYield}[/color]
|
seed-component-plant-yield-text = Plant Yield: [color=lightblue]{$seedYield}[/color]
|
||||||
|
|||||||
Reference in New Issue
Block a user