Files
space-station-14/Content.Server/Botany/Systems/BotanySystem.Seed.cs
T
kosticia d9e523370a Unite LogComponent, FoodSlicableComponent and partially ButcherableComponent into one. Sharp component removal. (#36895)
* Yay

* Do a LOT changes in yml

* and again

* Finale changes

* yml and locale

* locale tweak

* yml and charp cleanup

* fix carpets

* and some-some

* And some

* I want to believe that its last🙏🙏

* 😭

* 😭😭

* clean

* fix

* AAHHAHAHAHAHAH

* fix

* FINAL

* thisguyusa...

* LAST_ONE

* wawa

* merge2

* sdobfjibwdsjaqaksmzxsowaw2edqw84

* aoaoaooaoaao

* this hardcode took 30 minutes of my life

* fix aaaa

* fix test

* FIX BUILD

* oops

* oops

* aaooaoaoa

* fuck

* oops

* refactor: cleanup after merge + use protoId in KitchenSpikeComponent

* refactor: fix butcherable stuff again!~

* fix: now actively checks for EdibleComponent on slicing, predicted items splitting

* fix: changed knife.yaml to use Slicing tool

* fix: no more sounds spam on chop-chop

* refactor: cleanups

* refactor: default time value for slicable

* refactor: whitespaces and extract variables

* fix: slicable no longer prevents InteractUsingEvent by marking handled w/o actually handling

* feat: chopping trees now requires sawing tool, same for slicing logs

* refactor: cleanup after merge

* refactor: fix non-related PR changes

* refactor: rename locid

* refactor: remove unneeded red 'slice' verb name when slicing entities with mob-state.

* refactor: simplify test code changes

* refactor: better readability for test

* refactor: linebreak for unary op

* refactor: xml-doc for SliceableComponent corrected to be more fitting.

* refactor: cleanup SliceableSystem some more

* refactor: use HasComp instead of TryComp in AddSliceVerb

* refactor: extracted methods to improve readability

* refactor: remove unchecked operator - not needed when casting from uint

* refactor: SliceableSystem cleanups, fix logs not being chopped due to solution splitting

* fix: slice verb is now showing up even if disabled, slicing is done even if there is no solution to split, replaced direct dependency for sliceable component to food component with default solution-name

* refactor: comment about RandomPredicted + toy knife now fits into clown shoes

* refactor: remove EdibleComponent dependency from SliceableSystem

* refactor: moved SliceableSystem into ToolRefinableSystem

* refactor: basic renaming for comps

* refactor: cleanup after merge

* refactor: reorder methods, renaming, simplify polymorph related conditions on slicing

* refactor: xml-doc + reorder yaml fields

* refactor: fixing yaml + method renaming, unused usings removed

* refactor: removed unused usings

* refactor: fix typo

* refactor: remove reference for deleted meat proto

* refactor: clean up yaml after merge

* refactor: fix multiple typos from mass replace

* refactor: fix missed field renaming

* refactor: ensure all entities that had ToolRefinable got BaseSlicingRefinable (aftermerge cleanup)

* refactor: undo solution-related changes for animals.yml

* refactor: fix invalid parent set for corgi + fix amount of slices for the rest of pies

* refactor: revert Solution to SolutionContainerManager changes after merge

* refactor: revert Solution to SolutionContainerManager changes after merge

* refactor: fix invalid property name for toolMissingQualityTooltip in yml, fixed missing entity on which AttemptToolRefineEvent is raised

* refactor: remove over-indent for components of BaseSlicingRefinable and for Slicing tool quality

* refactor: remove over-indentation on MobCarpHolo

* empty collection

---------

Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
Co-authored-by: Fildrance <fildrance@gmail.com>
Co-authored-by: iaada <iaada@users.noreply.github.com>
2026-05-28 20:47:49 +00:00

206 lines
7.1 KiB
C#

using Content.Server.Botany.Components;
using Content.Server.Popups;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Botany;
using Content.Shared.Examine;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Popups;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Tools.Systems;
using Content.Shared.Tools;
namespace Content.Server.Botany.Systems;
public sealed partial class BotanySystem : EntitySystem
{
[Dependency] private IPrototypeManager _prototypeManager = default!;
[Dependency] private IRobustRandom _robustRandom = default!;
[Dependency] private AppearanceSystem _appearance = default!;
[Dependency] private PopupSystem _popupSystem = default!;
[Dependency] private SharedHandsSystem _hands = default!;
[Dependency] private SharedSolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private MetaDataSystem _metaData = default!;
[Dependency] private RandomHelperSystem _randomHelper = default!;
[Dependency] private ISharedAdminLogManager _adminLogger = default!;
[Dependency] private SharedToolSystem _tools = default!;
private static readonly ProtoId<ToolQualityPrototype> HarvestTool = "Slicing";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SeedComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<ProduceComponent, ExaminedEvent>(OnProduceExamined);
}
public bool TryGetSeed(SeedComponent comp, [NotNullWhen(true)] out SeedData? seed)
{
if (comp.Seed != null)
{
seed = comp.Seed;
return true;
}
if (comp.SeedId != null
&& _prototypeManager.TryIndex(comp.SeedId, out SeedPrototype? protoSeed))
{
seed = protoSeed;
return true;
}
seed = null;
return false;
}
public bool TryGetSeed(ProduceComponent comp, [NotNullWhen(true)] out SeedData? seed)
{
if (comp.Seed != null)
{
seed = comp.Seed;
return true;
}
if (comp.SeedId != null
&& _prototypeManager.TryIndex(comp.SeedId, out SeedPrototype? protoSeed))
{
seed = protoSeed;
return true;
}
seed = null;
return false;
}
private void OnExamined(EntityUid uid, SeedComponent component, ExaminedEvent args)
{
if (!args.IsInDetailsRange)
return;
if (!TryGetSeed(component, out var seed))
return;
using (args.PushGroup(nameof(SeedComponent), 1))
{
var name = Loc.GetString(seed.DisplayName);
args.PushMarkup(Loc.GetString($"seed-component-description", ("seedName", name)));
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
/// <summary>
/// Spawns a new seed packet on the floor at a position, then tries to put it in the user's hands if possible.
/// </summary>
public EntityUid SpawnSeedPacket(SeedData proto, EntityCoordinates coords, EntityUid user, float? healthOverride = null)
{
var seed = Spawn(proto.PacketPrototype, coords);
var seedComp = EnsureComp<SeedComponent>(seed);
seedComp.Seed = proto;
seedComp.HealthOverride = healthOverride;
var name = Loc.GetString(proto.Name);
var noun = Loc.GetString(proto.Noun);
var val = Loc.GetString("botany-seed-packet-name", ("seedName", name), ("seedNoun", noun));
_metaData.SetEntityName(seed, val);
// try to automatically place in user's other hand
_hands.TryPickupAnyHand(user, seed);
return seed;
}
public IEnumerable<EntityUid> AutoHarvest(SeedData proto, EntityCoordinates position, int yieldMod = 1)
{
if (position.IsValid(EntityManager) &&
proto.ProductPrototypes.Count > 0)
{
if (proto.HarvestLogImpact != null)
_adminLogger.Add(LogType.Botany, proto.HarvestLogImpact.Value, $"Auto-harvested {Loc.GetString(proto.Name):seed} at Pos:{position}.");
return GenerateProduct(proto, position, yieldMod);
}
return Enumerable.Empty<EntityUid>();
}
public IEnumerable<EntityUid> Harvest(SeedData proto, EntityUid user, int yieldMod = 1)
{
if (proto.ProductPrototypes.Count == 0 || proto.Yield <= 0)
{
_popupSystem.PopupCursor(Loc.GetString("botany-harvest-fail-message"), user, PopupType.Medium);
return Enumerable.Empty<EntityUid>();
}
var name = Loc.GetString(proto.DisplayName);
_popupSystem.PopupCursor(Loc.GetString("botany-harvest-success-message", ("name", name)), user, PopupType.Medium);
if (proto.HarvestLogImpact != null)
_adminLogger.Add(LogType.Botany, proto.HarvestLogImpact.Value, $"{ToPrettyString(user):player} harvested {Loc.GetString(proto.Name):seed} at Pos:{Transform(user).Coordinates}.");
return GenerateProduct(proto, Transform(user).Coordinates, yieldMod);
}
public IEnumerable<EntityUid> GenerateProduct(SeedData proto, EntityCoordinates position, int yieldMod = 1)
{
var totalYield = 0;
if (proto.Yield > -1)
{
if (yieldMod < 0)
totalYield = proto.Yield;
else
totalYield = proto.Yield * yieldMod;
totalYield = Math.Max(1, totalYield);
}
var products = new List<EntityUid>();
if (totalYield > 1 || proto.HarvestRepeat != HarvestType.NoRepeat)
proto.Unique = false;
for (var i = 0; i < totalYield; i++)
{
var product = _robustRandom.Pick(proto.ProductPrototypes);
var entity = Spawn(product, position);
_randomHelper.RandomOffset(entity, 0.25f);
products.Add(entity);
var produce = EnsureComp<ProduceComponent>(entity);
produce.Seed = proto;
ProduceGrown(entity, produce);
_appearance.SetData(entity, ProduceVisuals.Potency, proto.Potency);
if (proto.Mysterious)
{
var metaData = MetaData(entity);
_metaData.SetEntityName(entity, metaData.EntityName + "?", metaData);
_metaData.SetEntityDescription(entity,
metaData.EntityDescription + " " + Loc.GetString("botany-mysterious-description-addon"), metaData);
}
}
return products;
}
public bool CanHarvest(SeedData proto, EntityUid? held = null)
{
return !proto.Ligneous || proto.Ligneous && held != null && _tools.HasQuality(held.Value, HarvestTool);
}
#endregion
}