Farming WIP (#269)

* setup planting doafter

* spawn plants after use seed

* some work

* move comps to separate folder

* public check daylight

* daylight plant energy regeneration

* some fixes

* bruh, im thinking

* added ingame soil

* added hoe

* attaching plants

* hoe system

* block plant dublicating

* some planting refactor

* shovel as pant + soil remover

* plant growing visualizer

* soil resprite

* split farming system to second partial class

* update throught event refactor

* tring sync update plant with update visuals

* finish visual sync

* plants growing

* more partial splitting, naming work, clean up

* Update FARMINGTEST.yml

* Update FARMINGTEST.yml

* fix typo

* prototype value validating

* Оно бухает воду!

* solution visualizer in soil

* forgot some fix

* part of Tornado review fix

* destroy RemovePlantComponent

* more fixes

* simple harvesting

* refactor plant component values changing

* harvest redo

* gather on destroyByTool

* sickle resprite

* plant fading

* fading per minute!

* wheat sprites

* YML restruct

* fixes

* auto root plants

* add comments

* move sprites

* split structures from object textures

* wheat farming!

* Update CP14FarmingSystem.Interactions.cs

* seedbed (#297)

seedbed :^)

* a

* Update soil.yml

---------

Co-authored-by: Jaraten <116667537+Jaraten@users.noreply.github.com>
This commit is contained in:
Ed
2024-07-15 23:58:03 +03:00
committed by GitHub
parent 2de26baebd
commit 8cbd26ae2f
132 changed files with 1584 additions and 152 deletions

View File

@@ -0,0 +1,23 @@
namespace Content.Client._CP14.Farming;
/// <summary>
/// Controls the visual display of plant growth
/// </summary>
[RegisterComponent]
public sealed partial class CP14PlantVisualsComponent : Component
{
[DataField]
public int GrowthSteps = 3;
[DataField]
public string? GrowState;
[DataField]
public string? GrowUnshadedState;
}
public enum PlantVisualLayers : byte
{
Base,
BaseUnshaded,
}

View File

@@ -0,0 +1,48 @@
using Content.Shared._CP14.Farming;
using Content.Shared.Rounding;
using Robust.Client.GameObjects;
namespace Content.Client._CP14.Farming;
public sealed class ClientCP14FarmingSystem : CP14SharedFarmingSystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14PlantVisualsComponent, ComponentInit>(OnPlantVisualInit);
SubscribeLocalEvent<CP14PlantComponent, AfterAutoHandleStateEvent>(OnAutoHandleState);
}
private void OnAutoHandleState(Entity<CP14PlantComponent> plant, ref AfterAutoHandleStateEvent args)
{
if (!TryComp<CP14PlantVisualsComponent>(plant, out var visuals))
return;
UpdateVisuals(new Entity<CP14PlantVisualsComponent>(plant, visuals));
}
private void OnPlantVisualInit(Entity<CP14PlantVisualsComponent> visuals, ref ComponentInit args)
{
UpdateVisuals(visuals);
}
private void UpdateVisuals(Entity<CP14PlantVisualsComponent> visuals)
{
if (!TryComp<SpriteComponent>(visuals, out var sprite))
return;
if (!TryComp<CP14PlantComponent>(visuals, out var plant))
return;
var growthState = ContentHelpers.RoundToNearestLevels(plant.GrowthLevel, 1, visuals.Comp.GrowthSteps);
if (growthState == 0)
growthState++;
if (sprite.LayerMapTryGet(PlantVisualLayers.Base, out _))
sprite.LayerSetState(PlantVisualLayers.Base, $"{visuals.Comp.GrowState}{growthState}");
if (sprite.LayerMapTryGet(PlantVisualLayers.BaseUnshaded, out _))
sprite.LayerSetState(PlantVisualLayers.BaseUnshaded, $"{visuals.Comp.GrowUnshadedState}{growthState}");
}
}

View File

@@ -0,0 +1,153 @@
using Content.Server._CP14.Farming.Components;
using Content.Server.Gatherable.Components;
using Content.Shared._CP14.Farming;
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
using Content.Shared.Weapons.Melee.Events;
namespace Content.Server._CP14.Farming;
public sealed partial class CP14FarmingSystem
{
private void InitializeInteractions()
{
SubscribeLocalEvent<CP14SeedComponent, AfterInteractEvent>(OnSeedInteract);
SubscribeLocalEvent<CP14PlantGatherableComponent, ActivateInWorldEvent>(OnActivate);
SubscribeLocalEvent<CP14PlantGatherableComponent, AttackedEvent>(OnAttacked);
SubscribeLocalEvent<CP14SoilComponent, PlantSeedDoAfterEvent>(OnSeedPlantedDoAfter);
}
private void OnAttacked(Entity<CP14PlantGatherableComponent> gatherable, ref AttackedEvent args)
{
if (_whitelist.IsWhitelistFailOrNull(gatherable.Comp.ToolWhitelist, args.Used))
return;
TryHarvestPlant(gatherable, out _);
}
private void OnActivate(Entity<CP14PlantGatherableComponent> gatherable, ref ActivateInWorldEvent args)
{
if (args.Handled || !args.Complex)
return;
if (_whitelist.IsWhitelistFailOrNull(gatherable.Comp.ToolWhitelist, args.User))
return;
TryHarvestPlant(gatherable, out _);
args.Handled = true;
}
public bool TryHarvestPlant(Entity<CP14PlantGatherableComponent> gatheredPlant, out HashSet<EntityUid> result, EntityUid? gatherer = null)
{
result = new();
if (!TryComp<CP14PlantComponent>(gatheredPlant, out var plant))
return false;
if (plant.GrowthLevel < gatheredPlant.Comp.GrowthLevelToHarvest)
return false;
if (TryComp<SoundOnGatherComponent>(gatheredPlant, out var soundComp))
{
_audio.PlayPvs(soundComp.Sound, Transform(gatheredPlant).Coordinates);
}
if (gatheredPlant.Comp.Loot == null)
return false;
var pos = _transform.GetMapCoordinates(gatheredPlant);
foreach (var (tag, table) in gatheredPlant.Comp.Loot)
{
if (tag != "All")
{
if (gatherer != null && !_tag.HasTag(gatherer.Value, tag))
continue;
}
if (!_proto.TryIndex(table, out var getLoot))
continue;
var spawnLoot = getLoot.GetSpawns(_random);
var spawnPos = pos.Offset(_random.NextVector2(gatheredPlant.Comp.GatherOffset));
result.Add(Spawn(spawnLoot[0], spawnPos)); //TODO почему то не спавнится больше 1 пшенички. Кажись проблема оффов
}
if (gatheredPlant.Comp.DeleteAfterHarvest)
_destructible.DestroyEntity(gatheredPlant);
else
AffectGrowth((gatheredPlant, plant), -gatheredPlant.Comp.GrowthCostHarvest);
return true;
}
private void OnSeedInteract(Entity<CP14SeedComponent> seed, ref AfterInteractEvent args)
{
if (args.Handled)
return;
if (!TryComp<CP14SoilComponent>(args.Target, out var soil))
return;
if (EntityManager.EntityExists(soil.PlantUid))
{
_popup.PopupEntity(Loc.GetString("cp14-farming-soil-interact-plant-exist"), args.Target.Value, args.User);
return;
}
var doAfterArgs =
new DoAfterArgs(EntityManager, args.User, seed.Comp.PlantingTime, new PlantSeedDoAfterEvent(), args.Target, args.Used, args.Target)
{
BreakOnDamage = true,
BlockDuplicate = true,
BreakOnMove = true,
BreakOnHandChange = true,
};
_doAfter.TryStartDoAfter(doAfterArgs);
args.Handled = true;
}
public bool TryPlantSeed(EntityUid seed, EntityUid soil, EntityUid? user)
{
if (!TryComp<CP14SoilComponent>(soil, out var soilComp))
return false;
if (!TryComp<CP14SeedComponent>(seed, out var seedComp))
return false;
if (Exists(soilComp.PlantUid))
{
if (user is not null)
_popup.PopupEntity(Loc.GetString("cp14-farming-soil-interact-plant-exist"), soil, user.Value);
return false;
}
var plant = SpawnAttachedTo(seedComp.PlantProto, Transform(soil).Coordinates);
if (!TryComp<CP14PlantComponent>(plant, out var plantComp))
return false;
_transform.SetParent(plant, soil);
soilComp.PlantUid = plant;
plantComp.SoilUid = soil;
return true;
}
private void OnSeedPlantedDoAfter(Entity<CP14SoilComponent> soil, ref PlantSeedDoAfterEvent args)
{
if (args.Cancelled || args.Handled || args.Args.Used == null || args.Target == null)
return;
if (!TryPlantSeed(args.Target.Value, soil, args.User))
return;
//Audio
QueueDel(args.Target); //delete seed
args.Handled = true;
}
}

View File

@@ -0,0 +1,87 @@
using Content.Server._CP14.Farming.Components;
using Content.Shared._CP14.Farming;
using Content.Shared.Chemistry.Components.SolutionManager;
namespace Content.Server._CP14.Farming;
public sealed partial class CP14FarmingSystem
{
private void InitializeResources()
{
SubscribeLocalEvent<CP14PlantEnergyFromLightComponent, CP14PlantUpdateEvent>(OnTakeEnergyFromLight);
SubscribeLocalEvent<CP14PlantMetabolizerComponent, CP14PlantUpdateEvent>(OnPlantMetabolizing);
SubscribeLocalEvent<CP14PlantFadingComponent, CP14PlantUpdateEvent>(OnPlantFade);
SubscribeLocalEvent<CP14PlantGrowingComponent, CP14AfterPlantUpdateEvent>(OnPlantGrowing);
}
private void OnPlantFade(Entity<CP14PlantFadingComponent> ent, ref CP14PlantUpdateEvent args)
{
var realFade = ent.Comp.ResourcePerMinute * (float)args.Plant.Comp.Age.TotalMinutes;
if (args.Plant.Comp.Resource < realFade)
{
_damageable.TryChangeDamage(ent, ent.Comp.FadeDamage, true);
}
AffectResource(args.Plant, -realFade);
}
private void OnTakeEnergyFromLight(Entity<CP14PlantEnergyFromLightComponent> regeneration, ref CP14PlantUpdateEvent args)
{
var gainEnergy = false;
var daylight = _dayCycle.TryDaylightThere(regeneration, true);
if (regeneration.Comp.Daytime && daylight)
gainEnergy = true;
if (regeneration.Comp.Nighttime && !daylight)
gainEnergy = true;
if (gainEnergy)
args.EnergyDelta += regeneration.Comp.Energy;
}
private void OnPlantGrowing(Entity<CP14PlantGrowingComponent> growing, ref CP14AfterPlantUpdateEvent args)
{
if (args.Plant.Comp.Energy < growing.Comp.EnergyCost)
return;
if (args.Plant.Comp.Resource < growing.Comp.ResourceCost)
return;
if (args.Plant.Comp.GrowthLevel >= 1)
return;
AffectEnergy(args.Plant, -growing.Comp.EnergyCost);
AffectResource(args.Plant, -growing.Comp.ResourceCost);
AffectGrowth(args.Plant, growing.Comp.GrowthPerUpdate);
}
private void OnPlantMetabolizing(Entity<CP14PlantMetabolizerComponent> ent, ref CP14PlantUpdateEvent args)
{
if (args.Plant.Comp.SoilUid == null ||
!TryComp<CP14SoilComponent>(args.Plant.Comp.SoilUid, out var soil) ||
!TryComp<CP14PlantComponent>(ent, out var plant) ||
!TryComp<SolutionContainerManagerComponent>(args.Plant.Comp.SoilUid, out var solmanager))
return;
var solEntity = new Entity<SolutionContainerManagerComponent?>(args.Plant.Comp.SoilUid.Value, solmanager);
if (!_solutionContainer.TryGetSolution(solEntity, soil.Solution, out var soln, out var solution))
return;
if (!_proto.TryIndex(ent.Comp.MetabolizerId, out var metabolizer))
return;
var splitted = _solutionContainer.SplitSolution(soln.Value, ent.Comp.SolutionPerUpdate);
foreach (var reagent in splitted)
{
if (!metabolizer.Metabolization.ContainsKey(reagent.Reagent.ToString()))
continue;
foreach (var effect in metabolizer.Metabolization[reagent.Reagent.ToString()])
{
effect.Effect((ent, plant), reagent.Quantity, EntityManager);
}
}
}
}

View File

@@ -0,0 +1,114 @@
using Content.Server._CP14.Farming.Components;
using Content.Server.Destructible;
using Content.Server.DoAfter;
using Content.Server.Popups;
using Content.Shared._CP14.DayCycle;
using Content.Shared._CP14.Farming;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.Tag;
using Content.Shared.Whitelist;
using Robust.Server.Audio;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server._CP14.Farming;
public sealed partial class CP14FarmingSystem : CP14SharedFarmingSystem
{
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly CP14DayCycleSystem _dayCycle = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly DestructibleSystem _destructible = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
public override void Initialize()
{
base.Initialize();
InitializeInteractions();
InitializeResources();
SubscribeLocalEvent<CP14PlantComponent, EntityUnpausedEvent>(OnUnpaused);
SubscribeLocalEvent<CP14PlantComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<CP14PlantAutoRootComponent, MapInitEvent>(OnAutoRootMapInit);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<CP14PlantComponent>();
while (query.MoveNext(out var uid, out var plant))
{
if (_timing.CurTime <= plant.NextUpdateTime)
continue;
var newTime = _random.NextFloat(plant.UpdateFrequency);
plant.NextUpdateTime = _timing.CurTime + TimeSpan.FromSeconds(newTime);
plant.Age += TimeSpan.FromSeconds(plant.UpdateFrequency);
var ev = new CP14PlantUpdateEvent((uid, plant));
RaiseLocalEvent(uid, ev);
AffectResource((uid, plant), ev.ResourceDelta);
AffectEnergy((uid, plant), ev.EnergyDelta);
var ev2 = new CP14AfterPlantUpdateEvent((uid, plant));
RaiseLocalEvent(uid, ev2);
Dirty(uid, plant);
}
}
private void OnUnpaused(Entity<CP14PlantComponent> ent, ref EntityUnpausedEvent args)
{
ent.Comp.NextUpdateTime += args.PausedTime;
}
private void OnMapInit(Entity<CP14PlantComponent> plant, ref MapInitEvent args)
{
var newTime = _random.NextFloat(plant.Comp.UpdateFrequency);
plant.Comp.NextUpdateTime = _timing.CurTime + TimeSpan.FromSeconds(newTime);
}
private void OnAutoRootMapInit(Entity<CP14PlantAutoRootComponent> autoRoot, ref MapInitEvent args)
{
var grid = Transform(autoRoot).GridUid;
if (grid == null || !TryComp<MapGridComponent>(grid, out var gridComp))
return;
var targetPos = new EntityCoordinates(grid.Value,Transform(autoRoot).LocalPosition);
var anchored = _map.GetAnchoredEntities(grid.Value, gridComp, targetPos);
foreach (var entt in anchored)
{
if (!TryComp<CP14SoilComponent>(entt, out var soil))
continue;
_transform.SetParent(autoRoot, entt);
soil.PlantUid = autoRoot;
if (TryComp<CP14PlantComponent>(autoRoot, out var plantComp))
{
plantComp.SoilUid = entt;
}
break;
}
}
}

View File

@@ -0,0 +1,9 @@
namespace Content.Server._CP14.Farming.Components;
/// <summary>
/// when it init, it automatically attaches itself by its roots to the soil beneath it.
/// </summary>
[RegisterComponent, Access(typeof(CP14FarmingSystem))]
public sealed partial class CP14PlantAutoRootComponent : Component
{
}

View File

@@ -0,0 +1,17 @@
namespace Content.Server._CP14.Farming.Components;
/// <summary>
/// allows the plant to receive energy passively, depending on daylight
/// </summary>
[RegisterComponent, Access(typeof(CP14FarmingSystem))]
public sealed partial class CP14PlantEnergyFromLightComponent : Component
{
[DataField]
public float Energy = 0f;
[DataField]
public bool Daytime = true;
[DataField]
public bool Nighttime = false;
}

View File

@@ -0,0 +1,23 @@
using Content.Shared.Damage;
using Content.Shared.FixedPoint;
namespace Content.Server._CP14.Farming.Components;
/// <summary>
/// Gradually wastes the plant's resources, killing it if there aren't enough. The waste gradually increases over time, reflecting the "Old Age" of the plant
/// </summary>
[RegisterComponent, Access(typeof(CP14FarmingSystem))]
public sealed partial class CP14PlantFadingComponent : Component
{
[DataField]
public float ResourcePerMinute = 0f;
[DataField]
public DamageSpecifier FadeDamage = new()
{
DamageDict = new Dictionary<string, FixedPoint2>
{
{ "Cellular", 0.05 },
},
};
}

View File

@@ -0,0 +1,20 @@
namespace Content.Server._CP14.Farming.Components;
/// <summary>
/// Is trying to use up the plant's energy and resources to grow.
/// </summary>
[RegisterComponent, Access(typeof(CP14FarmingSystem))]
public sealed partial class CP14PlantGrowingComponent : Component
{
[DataField]
public float EnergyCost = 0f;
[DataField]
public float ResourceCost = 0f;
/// <summary>
/// for each plant renewal. It is not every frame, it depends on the refresh rate in PlantComponent
/// </summary>
[DataField]
public float GrowthPerUpdate = 0f;
}

View File

@@ -0,0 +1,18 @@
using Content.Shared._CP14.Farming.Prototypes;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Farming.Components;
/// <summary>
/// allows the plant to obtain resources by absorbing liquid from the ground
/// </summary>
[RegisterComponent, Access(typeof(CP14FarmingSystem))]
public sealed partial class CP14PlantMetabolizerComponent : Component
{
[DataField]
public FixedPoint2 SolutionPerUpdate = 5f;
[DataField(required: true)]
public ProtoId<CP14PlantMetabolizerPrototype> MetabolizerId;
}

View File

@@ -0,0 +1,16 @@
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Farming.Components;
/// <summary>
/// a component that allows for the creation of the plant entity on the soil
/// </summary>
[RegisterComponent, Access(typeof(CP14FarmingSystem))]
public sealed partial class CP14SeedComponent : Component
{
[DataField]
public TimeSpan PlantingTime = TimeSpan.FromSeconds(2f);
[DataField(required: true)]
public EntProtoId PlantProto;
}

View File

@@ -0,0 +1,13 @@
namespace Content.Server._CP14.Farming.Components;
/// <summary>
/// a component that provides a link to a liquid storage that can be used by the plant
/// </summary>
[RegisterComponent, Access(typeof(CP14FarmingSystem))]
public sealed partial class CP14SoilComponent : Component
{
[DataField(required: true)]
public string Solution = string.Empty;
public EntityUid? PlantUid;
}

View File

@@ -0,0 +1,21 @@
using Content.Shared._CP14.SpawnOnTileTool;
namespace Content.Server._CP14.SpawnOnTileTool;
public sealed partial class CP14SpawnOnTileToolSystem : SharedCP14SpawnOnTileToolSystem
{
public override void Initialize()
{
SubscribeLocalEvent<CP14SpawnOnTileToolComponent, SpawnOnTileToolAfterEvent>(AfterDoAfter);
}
private void AfterDoAfter(Entity<CP14SpawnOnTileToolComponent> ent, ref SpawnOnTileToolAfterEvent args)
{
if (args.Handled || args.Cancelled)
return;
SpawnAtPosition(args.Spawn, GetCoordinates(args.Coordinates));
args.Handled = true;
}
}

View File

@@ -1,3 +1,6 @@
using System.Diagnostics;
using Content.Shared.Maps;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
@@ -9,6 +12,9 @@ public sealed partial class CP14DayCycleSystem : EntitySystem
private const float MaxTimeDiff = 0.05f;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
public override void Initialize()
{
@@ -102,6 +108,35 @@ public sealed partial class CP14DayCycleSystem : EntitySystem
Dirty(dayCycle);
}
/// <summary>
/// Checks to see if the specified entity is on the map where it's daytime.
/// </summary>
/// <param name="target">An entity being tested to see if it is in daylight</param>
/// <param name="checkRoof">Checks if the tile covers the weather (the only "roof" factor at the moment)</param>
/// <param name="isDaylight">daylight test result returned</param>
public bool TryDaylightThere(EntityUid target, bool checkRoof)
{
if (!TryComp<TransformComponent>(target, out var xform))
return false;
if (!TryComp<CP14DayCycleComponent>(xform.MapUid, out var dayCycle))
return false;
if (checkRoof)
{
if (!TryComp<MapGridComponent>(xform.GridUid, out var mapGrid))
return !dayCycle.IsNight;
var tileRef = _maps.GetTileRef(xform.GridUid.Value, mapGrid, xform.Coordinates);
var tileDef = (ContentTileDefinition) _tileDefManager[tileRef.Tile.TypeId];
if (!tileDef.Weather)
return false;
}
return !dayCycle.IsNight;
}
private void SetAmbientColor(Entity<MapLightComponent> light, Color color)
{
if (color == light.Comp.AmbientLightColor)

View File

@@ -0,0 +1,17 @@
using Content.Shared.Tools;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.DestroyedByTool;
/// <summary>
/// abstract ability to destroy objects by using the right kind of tool on them
/// </summary>
[RegisterComponent, Access(typeof(CP14DestroyedByToolSystem))]
public sealed partial class CP14DestroyedByToolComponent : Component
{
[DataField]
public ProtoId<ToolQualityPrototype>? Tool;
[DataField]
public TimeSpan RemoveTime = TimeSpan.FromSeconds(1f);
}

View File

@@ -0,0 +1,59 @@
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
using Content.Shared.Tools.Components;
using Content.Shared.Tools.Systems;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.DestroyedByTool;
public sealed partial class CP14DestroyedByToolSystem : EntitySystem
{
[Dependency] private readonly SharedToolSystem _tool = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14DestroyedByToolComponent, CP14DestroyedByToolDoAfterEvent>(OnDestroyDoAfter);
SubscribeLocalEvent<CP14DestroyedByToolComponent, InteractUsingEvent>(OnInteractUsing);
}
private void OnInteractUsing(Entity<CP14DestroyedByToolComponent> ent, ref InteractUsingEvent args)
{
if (args.Handled)
return;
if (ent.Comp.Tool == null || !_tool.HasQuality(args.Used, ent.Comp.Tool))
return;
if (TryComp<ToolComponent>(args.Used, out var tool))
{
_tool.PlayToolSound(args.Used, tool, args.User);
}
var doAfterArgs =
new DoAfterArgs(EntityManager, args.User, ent.Comp.RemoveTime, new CP14DestroyedByToolDoAfterEvent(), args.Target)
{
BreakOnDamage = true,
BlockDuplicate = true,
BreakOnMove = true,
BreakOnHandChange = true,
};
_doAfter.TryStartDoAfter(doAfterArgs);
}
private void OnDestroyDoAfter(Entity<CP14DestroyedByToolComponent> ent, ref CP14DestroyedByToolDoAfterEvent args)
{
if (args.Cancelled || args.Handled)
return;
QueueDel(ent);
args.Handled = true;
}
}
[Serializable, NetSerializable]
public sealed partial class CP14DestroyedByToolDoAfterEvent : SimpleDoAfterEvent
{
}

View File

@@ -0,0 +1,75 @@
using Robust.Shared.GameStates;
namespace Content.Shared._CP14.Farming;
/// <summary>
/// The backbone of any plant. Provides common variables for the plant to other components, and a link to the soil
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), Access(typeof(CP14SharedFarmingSystem))]
public sealed partial class CP14PlantComponent : Component
{
/// <summary>
/// Soil link. May be null, as not all plants in the world grow on entity soil (e.g. wild shrubs)
/// </summary>
public EntityUid? SoilUid;
/// <summary>
/// The ability to consume a resource for growing
/// </summary>
[DataField]
public float Energy = 0f;
[DataField]
public float EnergyMax = 100f;
/// <summary>
/// resource consumed for growth
/// </summary>
[DataField]
public float Resource = 0f;
[DataField]
public float ResourceMax = 100f;
/// <summary>
/// Plant growth status, 0 to 1
/// </summary>
[DataField, AutoNetworkedField]
public float GrowthLevel = 0f;
[DataField(serverOnly: true)]
public float UpdateFrequency = 60f;
[DataField(serverOnly: true)]
public TimeSpan NextUpdateTime = TimeSpan.Zero;
[DataField(serverOnly: true)]
public TimeSpan Age = TimeSpan.Zero;
}
/// <summary>
/// Is called periodically at random intervals on the plant.
/// </summary>
public sealed class CP14PlantUpdateEvent : EntityEventArgs
{
public readonly Entity<CP14PlantComponent> Plant;
public float EnergyDelta = 0f;
public float ResourceDelta = 0f;
public CP14PlantUpdateEvent(Entity<CP14PlantComponent> comp)
{
Plant = comp;
}
}
/// <summary>
/// is called after CP14PlantUpdateEvent when all value changes have already been calculated.
/// </summary>
public sealed class CP14AfterPlantUpdateEvent : EntityEventArgs
{
public readonly Entity<CP14PlantComponent> Plant;
public CP14AfterPlantUpdateEvent(Entity<CP14PlantComponent> comp)
{
Plant = comp;
}
}

View File

@@ -0,0 +1,63 @@
using Content.Shared.EntityList;
using Content.Shared.Whitelist;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Farming;
/// <summary>
/// Means that the plant can be harvested.
/// </summary>
[RegisterComponent]
public sealed partial class CP14PlantGatherableComponent : Component
{
/// <summary>
/// Whitelist for specifying the kind of tools can be used on a resource
/// Supports multiple tags.
/// </summary>
[DataField(required: true)]
public EntityWhitelist ToolWhitelist = new();
/// <summary>
/// YAML example below
/// (Tag1, Tag2, LootTableID1, LootTableID2 are placeholders for example)
/// --------------------
/// useMappedLoot: true
/// toolWhitelist:
/// tags:
/// - Tag1
/// - Tag2
/// loot:
/// Tag1: LootTableID1
/// Tag2: LootTableID2
/// </summary>
[DataField]
public Dictionary<string, ProtoId<EntityLootTablePrototype>>? Loot = new();
/// <summary>
/// Random shift of the appearing entity during gathering
/// </summary>
[DataField]
public float GatherOffset = 0.3f;
[DataField]
public TimeSpan Time = TimeSpan.FromSeconds(1f);
/// <summary>
/// after harvesting, should the plant be completely removed?
/// </summary>
[DataField]
public bool DeleteAfterHarvest = false;
/// <summary>
/// after harvest, the growth level of the plant will be reduced by the specified value
/// </summary>
[DataField]
public float GrowthCostHarvest = 0.4f;
/// <summary>
/// what level of growth does a plant need to have before it can be harvested?
/// </summary>
[DataField]
public float GrowthLevelToHarvest = 0.9f;
}

View File

@@ -0,0 +1,37 @@
using Content.Shared.DoAfter;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.Farming;
public abstract partial class CP14SharedFarmingSystem : EntitySystem
{
public void AffectEnergy(Entity<CP14PlantComponent> ent, float energyDelta)
{
if (energyDelta == 0)
return;
ent.Comp.Energy = MathHelper.Clamp(ent.Comp.Energy + energyDelta, 0, ent.Comp.EnergyMax);
}
public void AffectResource(Entity<CP14PlantComponent> ent, float resourceDelta)
{
if (resourceDelta == 0)
return;
ent.Comp.Resource = MathHelper.Clamp(ent.Comp.Resource + resourceDelta, 0, ent.Comp.ResourceMax);
}
public void AffectGrowth(Entity<CP14PlantComponent> ent, float growthDelta)
{
if (growthDelta == 0)
return;
ent.Comp.GrowthLevel = MathHelper.Clamp01(ent.Comp.GrowthLevel + growthDelta);
Dirty(ent);
}
[Serializable, NetSerializable]
public sealed partial class PlantSeedDoAfterEvent : SimpleDoAfterEvent
{
}
}

View File

@@ -0,0 +1,23 @@
using Content.Shared._CP14.Farming.Prototypes;
using Content.Shared.FixedPoint;
namespace Content.Shared._CP14.Farming.Metabolizer;
public sealed partial class AffectPlantValues : CP14MetabolizerEffect
{
[DataField]
public float Energy = 0f;
[DataField]
public float Resource = 0f;
[DataField]
public float Growth = 0f;
public override void Effect(Entity<CP14PlantComponent> plant, FixedPoint2 amount, EntityManager entityManager)
{
var farmingSystem = entityManager.System<CP14SharedFarmingSystem>();
farmingSystem.AffectEnergy(plant, Energy * (float)amount);
farmingSystem.AffectResource(plant,Resource * (float)amount);
farmingSystem.AffectGrowth(plant, Growth * (float)amount);
}
}

View File

@@ -0,0 +1,27 @@
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Farming.Prototypes;
/// <summary>
/// Allows the plant to drink chemicals from the soil. The effect of the drank reagents depends on the selected metabolizer.
/// </summary>
[Prototype("CP14PlantMetabolizer")]
public sealed partial class CP14PlantMetabolizerPrototype : IPrototype
{
[ViewVariables]
[IdDataField]
public string ID { get; private set; } = string.Empty;
[DataField]
public Dictionary<ProtoId<ReagentPrototype>, HashSet<CP14MetabolizerEffect>> Metabolization = new();
}
[ImplicitDataDefinitionForInheritors]
[MeansImplicitUse]
public abstract partial class CP14MetabolizerEffect
{
public abstract void Effect(Entity<CP14PlantComponent> plant, FixedPoint2 amount, EntityManager entityManager);
}

View File

@@ -0,0 +1,43 @@
using Content.Shared.DoAfter;
using Content.Shared.Maps;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.SpawnOnTileTool;
/// <summary>
/// Allows using an item on a certain type of tile to spawn entities on it.
/// </summary>
[RegisterComponent, Access(typeof(SharedCP14SpawnOnTileToolSystem))]
public sealed partial class CP14SpawnOnTileToolComponent : Component
{
[DataField]
public Dictionary<ProtoId<ContentTileDefinition>, EntProtoId> Spawns = new();
[DataField]
public bool NeedEmptySpace = true;
[DataField]
public TimeSpan DoAfter = TimeSpan.FromSeconds(1f);
}
[Serializable, NetSerializable]
public sealed partial class SpawnOnTileToolAfterEvent : DoAfterEvent
{
public override DoAfterEvent Clone() => this;
public readonly NetCoordinates Coordinates;
public readonly EntProtoId Spawn;
public SpawnOnTileToolAfterEvent(IEntityManager entManager, EntityCoordinates coord, EntProtoId spawn)
{
Spawn = spawn;
Coordinates = entManager.GetNetCoordinates(coord);
}
public SpawnOnTileToolAfterEvent(NetCoordinates coord, EntProtoId spawn)
{
Spawn = spawn;
Coordinates = coord;
}
}

View File

@@ -0,0 +1,58 @@
using System.Linq;
using Content.Shared._CP14.Farming;
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
using Content.Shared.Maps;
using Content.Shared.Popups;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
namespace Content.Shared._CP14.SpawnOnTileTool;
public partial class SharedCP14SpawnOnTileToolSystem : EntitySystem
{
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly ITileDefinitionManager _tileDef = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14SpawnOnTileToolComponent, AfterInteractEvent>(OnAfterInteract);
}
private void OnAfterInteract(Entity<CP14SpawnOnTileToolComponent> tool, ref AfterInteractEvent args)
{
var grid = _transform.GetGrid(args.ClickLocation);
if (grid == null || !TryComp<MapGridComponent>(grid, out var gridComp))
return;
var tile = _map.GetTileRef(grid.Value, gridComp, args.ClickLocation);
var tileDef = (ContentTileDefinition) _tileDef[tile.Tile.TypeId];
if (tool.Comp.NeedEmptySpace && _map.GetAnchoredEntities(grid.Value, gridComp, args.ClickLocation).Count() > 0)
{
_popup.PopupClient(Loc.GetString("cp14-insufficient-space"), args.ClickLocation, args.User);
return;
}
foreach (var pair in tool.Comp.Spawns)
{
if (tileDef.ID != pair.Key)
continue;
var doAfterArgs =
new DoAfterArgs(EntityManager, args.User, tool.Comp.DoAfter, new SpawnOnTileToolAfterEvent(EntityManager, args.ClickLocation, pair.Value), tool)
{
BreakOnDamage = true,
BlockDuplicate = true,
BreakOnMove = true,
BreakOnHandChange = true
};
_doAfter.TryStartDoAfter(doAfterArgs);
break;
}
}
}

View File

@@ -1,3 +0,0 @@
# Crystal
popup-cp14crystal-ding = *ding*

View File

@@ -0,0 +1 @@
cp14-farming-soil-interact-plant-exist = There's already something planted here!

View File

@@ -0,0 +1,3 @@
popup-cp14crystal-ding = *ding*
cp14-insufficient-space = Insufficient space!

View File

@@ -1,3 +0,0 @@
# Crystal
popup-cp14crystal-ding = *дзынь*

View File

@@ -0,0 +1 @@
cp14-farming-soil-interact-plant-exist = Здесь уже что-то посажено!

View File

@@ -0,0 +1,3 @@
popup-cp14crystal-ding = *дзынь*
cp14-insufficient-space = Недостаточно места!

View File

@@ -0,0 +1,10 @@
- type: entity
id: CP14SeedTest
name: FUCK test SEED
parent: BaseItem
components:
- type: Sprite
sprite: Objects/Specific/Hydroponics/seeds.rsi
state: seed
- type: CP14Seed
plantProto: CP14PlantWheat

View File

@@ -8,7 +8,7 @@
- type: Sprite
layers:
- state: red
- sprite: _CP14/Objects/Specific/Alchemy/Herbal/agaric.rsi
- sprite: _CP14/Structures/Specific/Farming/Herbals/agaric.rsi
state: world1
- type: RandomSpawner
prototypes:

View File

@@ -0,0 +1,19 @@
- type: entity
id: CP14Wheat
parent: ProduceBase
name: wheat bushel
description: You have the choice of either planting the grains again or grinding them into flour.
components:
- type: Item
size: Tiny
- type: Produce
- type: Sprite
sprite: _CP14/Objects/Specific/Farming/Produce/wheat.rsi
layers:
- state: base1
map: ["random"]
- type: RandomSprite
available:
- random:
base1: ""
base2: ""

View File

@@ -12,7 +12,7 @@
size: Tiny
- type: Produce
- type: Sprite
sprite: _CP14/Objects/Specific/Alchemy/Herbal/bloodgrass.rsi
sprite: _CP14/Objects/Specific/Farming/Produce/bloodgrass.rsi
layers:
- state: base1
map: ["random"]
@@ -54,7 +54,7 @@
size: Tiny
- type: Produce
- type: Sprite
sprite: _CP14/Objects/Specific/Alchemy/Herbal/agaric.rsi
sprite: _CP14/Objects/Specific/Farming/Produce/agaric.rsi
layers:
- state: base1
map: ["random"]
@@ -93,7 +93,7 @@
size: Tiny
- type: Produce
- type: Sprite
sprite: _CP14/Objects/Specific/Alchemy/Herbal/chromium_slime.rsi
sprite: _CP14/Objects/Specific/Farming/Produce/chromium_slime.rsi
layers:
- state: base1
map: ["random"]
@@ -131,7 +131,7 @@
- 0,0,0,1
- type: Produce
- type: Sprite
sprite: _CP14/Objects/Specific/Alchemy/Herbal/wild_sage.rsi
sprite: _CP14/Objects/Specific/Farming/Produce/wild_sage.rsi
layers:
- state: base1
map: ["random"]
@@ -197,7 +197,7 @@
size: Tiny
- type: Produce
- type: Sprite
sprite: _CP14/Objects/Specific/Alchemy/Herbal/lumishroom.rsi
sprite: _CP14/Objects/Specific/Farming/Produce/lumishroom.rsi
layers:
- state: base1
map: ["random"]

View File

@@ -0,0 +1,53 @@
- type: entity
id: CP14Shovel
parent: BaseItem
name: shovel
description: An implement for digging up earth, digging beds or graves.
components:
- type: Sprite
sprite: _CP14/Objects/Tools/shovel.rsi
state: icon
- type: MeleeWeapon
wideAnimationRotation: 65
damage:
types:
Blunt: 5
Slash: 2
soundHit:
collection: MetalThud
- type: Item
size: Normal
sprite: _CP14/Objects/Tools/shovel.rsi
- type: ToolTileCompatible
- type: Tool
qualities:
- CP14Digging
useSound:
collection: CP14Digging
params:
variation: 0.03
volume: 2
- type: entity
id: CP14Hoe
parent: BaseItem
name: hoe
description: A gardening tool to prepare the soil for planting, or to clear weeds
components:
- type: Sprite
sprite: _CP14/Objects/Tools/hoe.rsi
state: icon
- type: MeleeWeapon
wideAnimationRotation: 65
damage:
types:
Piercing: 5
Slash: 2
soundHit:
collection: MetalThud
- type: Item
size: Normal
sprite: _CP14/Objects/Tools/hoe.rsi
- type: CP14SpawnOnTileTool
spawns:
CP14FloorDirt: CP14PloughedGround

View File

@@ -1,29 +0,0 @@
- type: entity
id: CP14Shovel
parent: BaseItem
name: shovel
description: An implement for digging up earth, digging beds or graves.
components:
- type: Sprite
sprite: _CP14/Objects/Tools/shovel.rsi
state: icon
- type: MeleeWeapon
wideAnimationRotation: 45
damage:
types:
Blunt: 7
Slash: 3
soundHit:
collection: MetalThud
- type: Item
size: Normal
sprite: _CP14/Objects/Tools/shovel.rsi
- type: ToolTileCompatible
- type: Tool
qualities:
- CP14Digging
useSound:
collection: CP14Digging
params:
variation: 0.03
volume: 2

View File

@@ -0,0 +1,70 @@
- type: entity
id: CP14GatherableBase
parent: BaseStructure
abstract: true
components:
- type: Sprite
snapCardinals: true
- type: Transform
anchored: true
- type: Physics
canCollide: false
bodyType: Static
- type: CP14DestroyedByTool
tool: CP14Digging
- type: CP14PlantAutoRoot
- type: Damageable
damageContainer: Biological
- type: MeleeSound
soundGroups:
Brute:
collection: CP14GrassGathering
params:
variation: 0.03
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 25
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- trigger:
!type:DamageTypeTrigger
damageType: Cellular
damage: 1
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: entity
id: CP14GatherableWildBase
parent: CP14GatherableBase
abstract: true
components:
- type: Tag
tags:
- HideContextMenu
- type: Gatherable
toolWhitelist:
tags:
- CP14HerbalGathering
- type: entity
id: CP14GatherablePlantBase
parent: CP14GatherableBase
abstract: true
components:
- type: InteractionOutline
- type: Appearance
- type: CP14PlantVisuals
growthSteps: 5
growState: "grow-"
- type: CP14Plant
resource: 10
energy: 0
growthLevel: 0
- type: CP14PlantGatherable
toolWhitelist:
tags:
- CP14HerbalGathering

View File

@@ -0,0 +1,67 @@
- type: entity
id: CP14PlantWheat
parent: CP14GatherablePlantBase
name: wheat
description: Most popular crop. Unpretentious, it opens the way to an abundance of flour products.
components:
- type: Sprite
sprite: _CP14/Structures/Specific/Farming/Herbals/wheat.rsi
layers:
- state: grow-1
map: ["enum.PlantVisualLayers.Base"]
- type: CP14PlantMetabolizer
metabolizerId: Base
- type: CP14PlantEnergyFromLight
energy: 1
daytime: true
- type: CP14PlantGrowing
energyCost: 1
resourceCost: 1
growthPerUpdate: 0.1 # 10 minute to full grow
- type: CP14PlantFading
resourcePerMinute: 0.25 #20 minute from water
- type: CP14PlantGatherable
deleteAfterHarvest: true
loot:
All: CP14GatherWheat
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 25
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- trigger:
!type:DamageTypeTrigger
damageType: Cellular
damage: 1
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- !type:SpawnEntitiesBehavior
spawn:
CP14PlantWheatDeath:
min: 1
max: 1
- type: entity
id: CP14PlantWheatDeath
name: dead wheat
description: The sad spectacle of wasted food.
parent: CP14GatherableBase
components:
- type: Sprite
sprite: _CP14/Structures/Specific/Farming/Herbals/wheat.rsi
state: death
- type: Gatherable
toolWhitelist:
tags:
- CP14HerbalGathering
- type: entityLootTable
id: CP14GatherWheat
entries:
- id: CP14Wheat
amount: 2
maxAmount: 4

View File

@@ -1,36 +1,3 @@
- type: entity
id: CP14GatherableHerbalBase
parent: BaseStructure
abstract: true
components:
- type: Transform
anchored: true
- type: Physics
canCollide: false
- type: Gatherable
toolWhitelist:
tags:
- CP14HerbalGathering
- type: Damageable
damageContainer: Inorganic
damageModifierSet: Wood
- type: MeleeSound
soundGroups:
Brute:
collection: CP14GrassGathering
params:
variation: 0.03
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 25
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Tag
tags:
- HideContextMenu
# Bloodgrass
@@ -43,15 +10,14 @@
- type: entity
id: CP14GatherableBloodgrass
parent: CP14GatherableHerbalBase
parent: CP14GatherableWildBase
name: bloodgrass
description: The dullest and most common plant to be found in the wild is the dark brown grass.
suffix: Gatherable
components:
- type: Sprite
snapCardinals: true
drawdepth: FloorTiles
sprite: _CP14/Objects/Specific/Alchemy/Herbal/bloodgrass.rsi
sprite: _CP14/Structures/Specific/Farming/Herbals/bloodgrass.rsi
layers:
- state: grass1
map: ["random"]
@@ -78,15 +44,14 @@
- type: entity
id: CP14GatherableFlyAgaric
parent: CP14GatherableHerbalBase
parent: CP14GatherableWildBase
name: fly agaric
description: This poisonous mushroom can often be found near bodies of water or other wet areas. It is not recommended for consumption.
suffix: Gatherable
components:
- type: Sprite
snapCardinals: true
drawdepth: FloorTiles
sprite: _CP14/Objects/Specific/Alchemy/Herbal/agaric.rsi
sprite: _CP14/Structures/Specific/Farming/Herbals/agaric.rsi
layers:
- state: world1
map: ["random"]
@@ -119,15 +84,14 @@
- type: entity
id: CP14GatherableChromiumSlime
parent: CP14GatherableHerbalBase
parent: CP14GatherableWildBase
name: chromium slime
description: This rare thick substance can be found in a stream of water as if it has a mind of its own. When trying to change the slime itself - the slime changes the reagent it interacts with.
suffix: Gatherable
components:
- type: Sprite
snapCardinals: true
drawdepth: FloorTiles
sprite: _CP14/Objects/Specific/Alchemy/Herbal/chromium_slime.rsi
sprite: _CP14/Structures/Specific/Farming/Herbals/chromium_slime.rsi
layers:
- state: world1
map: ["random"]
@@ -155,15 +119,14 @@
- type: entity
id: CP14GatherableWildSage
parent: CP14GatherableHerbalBase
parent: CP14GatherableWildBase
name: wild sage
description: Root of this ubiquitous medicinal plant not bad at healing physical injuries, and inducing coughing.
suffix: Gatherable
components:
- type: Sprite
snapCardinals: true
drawdepth: FloorTiles
sprite: _CP14/Objects/Specific/Alchemy/Herbal/wild_sage.rsi
sprite: _CP14/Structures/Specific/Farming/Herbals/wild_sage.rsi
layers:
- state: world1
map: ["random"]
@@ -188,15 +151,14 @@
- type: entity
id: CP14GatherableLumiMushroom
parent: CP14GatherableHerbalBase
parent: CP14GatherableWildBase
name: lumishroom
description: A faintly luminous mushroom. Often used by alchemists as a means of concentrating solutions.
suffix: Gatherable
components:
- type: Sprite
snapCardinals: true
drawdepth: FloorTiles
sprite: _CP14/Objects/Specific/Alchemy/Herbal/lumishroom.rsi
sprite: _CP14/Structures/Specific/Farming/Herbals/lumishroom.rsi
layers:
- state: world1
map: ["random"]

View File

@@ -0,0 +1,88 @@
- type: entity
id: CP14BaseFarmingSoil
abstract: true
placement:
mode: SnapgridCenter
components:
- type: Clickable
- type: Physics
bodyType: Static
- type: Fixtures
fixtures:
fix1:
shape:
!type:PhysShapeAabb
bounds: "-0.45,-0.45,0.45,0.1"
density: 190
hard: false
mask:
- FullTileMask
layer:
- FullTileMask
- type: Appearance
- type: SolutionContainerManager
solutions:
soil:
maxVol: 200
- type: RefillableSolution
solution: soil
maxRefill: 50
- type: Transform
anchored: true
- type: CP14Soil
solution: soil
- type: CP14DestroyedByTool
tool: CP14Digging
- type: entity
name: ploughed ground
parent: CP14BaseFarmingSoil
id: CP14PloughedGround
components:
- type: Sprite
drawdepth: FloorTiles
sprite: _CP14/Structures/Specific/Farming/soil.rsi
layers:
- state: soil1
map: ["random"]
- state: liq-1 #Resprite this shit
map: ["enum.SolutionContainerLayers.Fill"]
visible: false
snapCardinals: true
- type: SolutionContainerVisuals
maxFillLevels: 4
fillBaseName: liq-
- type: RandomSprite
available:
- random:
soil1: ""
soil2: ""
soil3: ""
soil4: ""
- type: entity
name: seedbed
id: CP14SeedbedDefault
parent: CP14BaseFarmingSoil
components:
- type: Icon
sprite: _CP14/Structures/Specific/Farming/seedbed.rsi
state: seedbed_default
- type: SmoothEdge
- type: IconSmooth
key: walls
mode: NoSprite
- type: Sprite
drawdepth: FloorTiles
sprite: _CP14/Structures/Specific/Farming/seedbed.rsi
layers:
- state: seedbed_default
- map: [ "enum.EdgeLayer.South" ]
state: seedbed_default_south
- map: [ "enum.EdgeLayer.East" ]
state: seedbed_default_east
- map: [ "enum.EdgeLayer.North" ]
state: seedbed_default_north
- map: [ "enum.EdgeLayer.West" ]
state: seedbed_default_west
# snapCardinals: true (when you flip it over, you get a swastika)

View File

@@ -0,0 +1,6 @@
- type: CP14PlantMetabolizer
id: Base
metabolization:
CP14Water:
- !type:AffectPlantValues
resource: 1

View File

@@ -0,0 +1,26 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"license": "All rights reserved for the CrystallPunk14 project only",
"copyright": "Created by TheShuEd (Github) for CrystallPunk14",
"states": [
{
"name": "base1"
},
{
"name": "base2"
},
{
"name": "base3"
},
{
"name": "base4"
},
{
"name": "base5"
}
]
}

View File

@@ -0,0 +1,26 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"license": "CC-BY-SA-3.0",
"copyright": "Base Created by TheShuEd (Github) for CrystallPunk14, Grass taken from tgstation at commits https://github.com/tgstation/tgstation/commit/729d858807905263adab8b5a331c1d8a04982dd3, and recolored",
"states": [
{
"name": "base1"
},
{
"name": "base2"
},
{
"name": "base3"
},
{
"name": "base4"
},
{
"name": "base5"
}
]
}

View File

@@ -0,0 +1,20 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"license": "All rights reserved for the CrystallPunk14 project only",
"copyright": "Created by TheShuEd (Github) for CrystallPunk14",
"states": [
{
"name": "base1"
},
{
"name": "base2"
},
{
"name": "base3"
}
]
}

View File

@@ -0,0 +1,26 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"license": "All rights reserved for the CrystallPunk14 project only",
"copyright": "Created by TheShuEd (Github) for CrystallPunk14",
"states": [
{
"name": "base1"
},
{
"name": "base2"
},
{
"name": "base3"
},
{
"name": "base4"
},
{
"name": "base5"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

View File

@@ -0,0 +1,17 @@
{
"version": 1,
"license": "All rights reserved for the CrystallPunk14 project only",
"copyright": "Created by TheShuEd for CrystallPunk14",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "base1"
},
{
"name": "base2"
}
]
}

View File

@@ -0,0 +1,20 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"license": "All rights reserved for the CrystallPunk14 project only",
"copyright": "Created by Prazar for CrystallPunk14",
"states": [
{
"name": "base1"
},
{
"name": "base2"
},
{
"name": "base3"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

View File

@@ -0,0 +1,22 @@
{
"version": 1,
"license": "All rights reserved for the CrystallPunk14 project only",
"copyright": "Created by TheShuEd (Github) for CrystallPunk",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 B

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 748 B

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 B

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 B

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 526 B

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 B

After

Width:  |  Height:  |  Size: 587 B

View File

@@ -7,21 +7,6 @@
"license": "All rights reserved for the CrystallPunk14 project only",
"copyright": "Created by TheShuEd (Github) for CrystallPunk14",
"states": [
{
"name": "base1"
},
{
"name": "base2"
},
{
"name": "base3"
},
{
"name": "base4"
},
{
"name": "base5"
},
{
"name": "world1"
},

View File

@@ -7,21 +7,6 @@
"license": "CC-BY-SA-3.0",
"copyright": "Base Created by TheShuEd (Github) for CrystallPunk14, Grass taken from tgstation at commits https://github.com/tgstation/tgstation/commit/729d858807905263adab8b5a331c1d8a04982dd3, and recolored",
"states": [
{
"name": "base1"
},
{
"name": "base2"
},
{
"name": "base3"
},
{
"name": "base4"
},
{
"name": "base5"
},
{
"name": "grass1"
},

View File

@@ -7,15 +7,6 @@
"license": "All rights reserved for the CrystallPunk14 project only",
"copyright": "Created by TheShuEd (Github) for CrystallPunk14",
"states": [
{
"name": "base1"
},
{
"name": "base2"
},
{
"name": "base3"
},
{
"name": "world1",
"delays": [

View File

@@ -7,21 +7,6 @@
"license": "All rights reserved for the CrystallPunk14 project only",
"copyright": "Created by TheShuEd (Github) for CrystallPunk14",
"states": [
{
"name": "base1"
},
{
"name": "base2"
},
{
"name": "base3"
},
{
"name": "base4"
},
{
"name": "base5"
},
{
"name": "world1"
},

Some files were not shown because too many files have changed in this diff Show More