Botany (#2357)
* plants and seeds go brrrr * update plants * P L A N T * brrrr * Hydroponics actually work! How about that? * Reuse resource path in visualizer * They lied to us. * Several stuffs * more werk * Add a bunch of plants * Logs go brr. * Brrr moment. * Remove unused method * Important comment. * Seed inventory, yo! * tomato moment * Balance consumption * Makes hydroponics pourable * Adds plant metabolism effect for sugar, the same as glucose. * Eggplant moment * Apple moment * Corn moment * Chanterelle mushroom moment * prototype tweaks * Seed extractor moment * typo * IPlantMetabolizable doc improvement * I should trust my gut instinct more often. * egg-plant..... * localization * Make WaterLevel and NutritionLevel setters private * Less code repetition! Wooo!
This commit is contained in:
committed by
GitHub
parent
7c57d10531
commit
484eb0bba4
354
Content.Server/Botany/Seed.cs
Normal file
354
Content.Server/Botany/Seed.cs
Normal file
@@ -0,0 +1,354 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Botany;
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Utility;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
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;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
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,
|
||||
}
|
||||
*/
|
||||
|
||||
public struct SeedChemQuantity
|
||||
{
|
||||
public int Min;
|
||||
public int Max;
|
||||
public int PotencyDivisor;
|
||||
}
|
||||
|
||||
[Prototype("seed")]
|
||||
public class Seed : IPrototype, IIndexedPrototype, IExposeData
|
||||
{
|
||||
private const string SeedPrototype = "SeedBase";
|
||||
|
||||
public string ID { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique identifier of this seed. Do NOT set this.
|
||||
/// </summary>
|
||||
public int Uid { get; internal set; } = -1;
|
||||
|
||||
#region Tracking
|
||||
[ViewVariables] public string Name { get; set; }
|
||||
[ViewVariables] public string SeedName { get; set; }
|
||||
[ViewVariables] public string SeedNoun { get; set; }
|
||||
[ViewVariables] public string DisplayName { get; set; }
|
||||
[ViewVariables] public bool RoundStart { get; private set; }
|
||||
[ViewVariables] public bool Mysterious { get; set; }
|
||||
[ViewVariables] public bool Immutable { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Output
|
||||
[ViewVariables] public List<string> ProductPrototypes { get; set; }
|
||||
[ViewVariables] public Dictionary<string, SeedChemQuantity> Chemicals { get; set; }
|
||||
[ViewVariables] public Dictionary<Gas, float> ConsumeGasses { get; set; }
|
||||
[ViewVariables]public Dictionary<Gas, float> ExudeGasses { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Tolerances
|
||||
[ViewVariables] public float NutrientConsumption { get; set; }
|
||||
[ViewVariables] public float WaterConsumption { get; set; }
|
||||
[ViewVariables] public float IdealHeat { get; set; }
|
||||
[ViewVariables] public float HeatTolerance { get; set; }
|
||||
[ViewVariables] public float IdealLight { get; set; }
|
||||
[ViewVariables] public float LightTolerance { get; set; }
|
||||
[ViewVariables] public float ToxinsTolerance { get; set; }
|
||||
[ViewVariables] public float LowPressureTolerance { get; set; }
|
||||
[ViewVariables] public float HighPressureTolerance { get; set; }
|
||||
[ViewVariables] public float PestTolerance { get; set; }
|
||||
[ViewVariables] public float WeedTolerance { get; set; }
|
||||
#endregion
|
||||
|
||||
#region General traits
|
||||
[ViewVariables] public float Endurance { get; set; }
|
||||
[ViewVariables] public int Yield { get; set; }
|
||||
[ViewVariables] public float Lifespan { get; set; }
|
||||
[ViewVariables] public float Maturation { get; set; }
|
||||
[ViewVariables] public float Production { get; set; }
|
||||
[ViewVariables] public int GrowthStages { get; set; }
|
||||
[ViewVariables] public HarvestType HarvestRepeat { get; set; }
|
||||
[ViewVariables] public float Potency { get; set; }
|
||||
// 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; }
|
||||
public bool Ligneous { get; set; }
|
||||
// public bool Teleporting { get; set; }
|
||||
// public PlantJuicy Juicy { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Cosmetics
|
||||
[ViewVariables]public ResourcePath PlantRsi { get; set; }
|
||||
[ViewVariables] public string PlantIconState { get; set; }
|
||||
[ViewVariables] public bool Bioluminescent { get; set; }
|
||||
[ViewVariables] public Color BioluminescentColor { get; set; }
|
||||
[ViewVariables] public string SplatPrototype { get; set; }
|
||||
#endregion
|
||||
|
||||
|
||||
public void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
serializer.DataField(this, x => x.ID, "id", string.Empty);
|
||||
serializer.DataField(this, x => x.Name, "name", string.Empty);
|
||||
serializer.DataField(this, x => x.SeedName, "seedName", string.Empty);
|
||||
serializer.DataField(this, x => x.SeedNoun, "seedNoun", "seeds");
|
||||
serializer.DataField(this, x => x.DisplayName, "displayName", string.Empty);
|
||||
serializer.DataField(this, x => x.RoundStart, "roundStart", true);
|
||||
serializer.DataField(this, x => x.Mysterious, "mysterious", false);
|
||||
serializer.DataField(this, x => x.Immutable, "immutable", false);
|
||||
serializer.DataField(this, x => x.ProductPrototypes, "productPrototypes", new List<string>());
|
||||
serializer.DataField(this, x => x.Chemicals, "chemicals", new Dictionary<string, SeedChemQuantity>());
|
||||
serializer.DataField(this, x => x.ConsumeGasses, "consumeGasses", new Dictionary<Gas, float>());
|
||||
serializer.DataField(this, x => x.ExudeGasses, "exudeGasses", new Dictionary<Gas, float>());
|
||||
serializer.DataField(this, x => x.NutrientConsumption, "nutrientConsumption", 0.25f);
|
||||
serializer.DataField(this, x => x.WaterConsumption, "waterConsumption", 3f);
|
||||
serializer.DataField(this, x => x.IdealHeat, "idealHeat", 293f);
|
||||
serializer.DataField(this, x => x.HeatTolerance, "heatTolerance", 20f);
|
||||
serializer.DataField(this, x => x.IdealLight, "idealLight", 7f);
|
||||
serializer.DataField(this, x => x.LightTolerance, "lightTolerance", 5f);
|
||||
serializer.DataField(this, x => x.ToxinsTolerance, "toxinsTolerance", 4f);
|
||||
serializer.DataField(this, x => x.LowPressureTolerance, "lowPressureTolerance", 25f);
|
||||
serializer.DataField(this, x => x.HighPressureTolerance, "highPressureTolerance", 200f);
|
||||
serializer.DataField(this, x => x.PestTolerance, "pestTolerance", 5f);
|
||||
serializer.DataField(this, x => x.WeedTolerance, "weedTolerance", 5f);
|
||||
serializer.DataField(this, x => x.Endurance, "endurance", 100f);
|
||||
serializer.DataField(this, x => x.Yield, "yield", 0);
|
||||
serializer.DataField(this, x => x.Lifespan, "lifespan", 0f);
|
||||
serializer.DataField(this, x => x.Maturation, "maturation", 0f);
|
||||
serializer.DataField(this, x => x.Production, "production", 0f);
|
||||
serializer.DataField(this, x => x.GrowthStages, "growthStages", 6);
|
||||
serializer.DataField(this, x => x.HarvestRepeat, "harvestRepeat", HarvestType.NoRepeat);
|
||||
serializer.DataField(this, x => x.Potency, "potency", 1f);
|
||||
serializer.DataField(this, x => x.Ligneous, "ligneous", false);
|
||||
serializer.DataField(this, x => x.PlantRsi, "plantRsi", null);
|
||||
serializer.DataField(this, x => x.PlantIconState, "plantIconState", "produce");
|
||||
serializer.DataField(this, x => x.Bioluminescent, "bioluminescent", false);
|
||||
serializer.DataField(this, x => x.BioluminescentColor, "bioluminescentColor", Color.White);
|
||||
serializer.DataField(this, x => x.SplatPrototype, "splatPrototype", string.Empty);
|
||||
}
|
||||
|
||||
public void LoadFrom(YamlMappingNode mapping)
|
||||
{
|
||||
var serializer = YamlObjectSerializer.NewReader(mapping);
|
||||
ExposeData(serializer);
|
||||
}
|
||||
|
||||
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 IEntity 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 (seed.TryGetComponent(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"));
|
||||
}
|
||||
|
||||
seed.Name = Loc.GetString($"packet of {SeedName} {SeedNoun}");
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
private void AddToDatabase()
|
||||
{
|
||||
var plantSystem = EntitySystem.Get<PlantSystem>();
|
||||
if (plantSystem.AddSeedToDatabase(this))
|
||||
{
|
||||
Name = Uid.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IEntity> AutoHarvest(EntityCoordinates position, int yieldMod = 1)
|
||||
{
|
||||
if (position.IsValid(IoCManager.Resolve<IEntityManager>()) && ProductPrototypes != null &&
|
||||
ProductPrototypes.Count > 0)
|
||||
return GenerateProduct(position, yieldMod);
|
||||
|
||||
return Enumerable.Empty<IEntity>();
|
||||
}
|
||||
|
||||
public IEnumerable<IEntity> Harvest(IEntity user, int yieldMod = 1)
|
||||
{
|
||||
AddToDatabase();
|
||||
|
||||
if (user == null)
|
||||
return Enumerable.Empty<IEntity>();
|
||||
|
||||
if (ProductPrototypes == null || ProductPrototypes.Count == 0 || Yield <= 0)
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("You fail to harvest anything useful."));
|
||||
return Enumerable.Empty<IEntity>();
|
||||
}
|
||||
|
||||
user.PopupMessageCursor(Loc.GetString($"You harvest from the {DisplayName}"));
|
||||
return GenerateProduct(user.Transform.Coordinates, yieldMod);
|
||||
}
|
||||
|
||||
public IEnumerable<IEntity> 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<IEntity>();
|
||||
|
||||
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)
|
||||
{
|
||||
entity.Name += "?";
|
||||
entity.Description += Loc.GetString(" On second thought, something about this one looks strange.");
|
||||
}
|
||||
}
|
||||
|
||||
return products;
|
||||
}
|
||||
|
||||
public Seed Diverge(bool modified)
|
||||
{
|
||||
return Clone();
|
||||
}
|
||||
|
||||
public bool CheckHarvest(IEntity user, IEntity held = null)
|
||||
{
|
||||
return (!Ligneous || (Ligneous && held != null && held.HasComponent<BotanySharpComponent>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user