diff --git a/Content.Server/Chemistry/Components/SolutionManager/RandomFillSolutionComponent.cs b/Content.Server/Chemistry/Components/SolutionManager/RandomFillSolutionComponent.cs
index bf75df03a7..409665fb0d 100644
--- a/Content.Server/Chemistry/Components/SolutionManager/RandomFillSolutionComponent.cs
+++ b/Content.Server/Chemistry/Components/SolutionManager/RandomFillSolutionComponent.cs
@@ -1,5 +1,4 @@
using Content.Server.Chemistry.EntitySystems;
-using Content.Shared.FixedPoint;
using Content.Shared.Random;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -18,14 +17,8 @@ public sealed class RandomFillSolutionComponent : Component
public string Solution { get; set; } = "default";
///
- /// Weighted random prototype Id. Used to pick reagent.
+ /// Weighted random fill prototype Id. Used to pick reagent and quantity.
///
- [DataField("weightedRandomId", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))]
+ [DataField("weightedRandomId", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))]
public string WeightedRandomId { get; set; } = "default";
-
- ///
- /// Amount of reagent to add.
- ///
- [DataField("quantity")]
- public FixedPoint2 Quantity { get; set; } = 0;
}
diff --git a/Content.Server/Chemistry/EntitySystems/SolutionRandomFillSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionRandomFillSystem.cs
index 0d653e1da9..78afda9910 100644
--- a/Content.Server/Chemistry/EntitySystems/SolutionRandomFillSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/SolutionRandomFillSystem.cs
@@ -20,18 +20,20 @@ public sealed class SolutionRandomFillSystem : EntitySystem
SubscribeLocalEvent(OnRandomSolutionFillMapInit);
}
- public void OnRandomSolutionFillMapInit(EntityUid uid, RandomFillSolutionComponent component, MapInitEvent args)
+ private void OnRandomSolutionFillMapInit(EntityUid uid, RandomFillSolutionComponent component, MapInitEvent args)
{
var target = _solutionsSystem.EnsureSolution(uid, component.Solution);
- var reagent = _proto.Index(component.WeightedRandomId).Pick(_random);
+ var pick = _proto.Index(component.WeightedRandomId).Pick(_random);
- if (!_proto.TryIndex(reagent, out ReagentPrototype? reagentProto))
+ var reagent = pick.reagent;
+ var quantity = pick.quantity;
+
+ if (!_proto.HasIndex(reagent))
{
- Logger.Error(
- $"Tried to add invalid reagent Id {reagent} using SolutionRandomFill.");
+ Log.Error($"Tried to add invalid reagent Id {reagent} using SolutionRandomFill.");
return;
}
- target.AddReagent(reagent, component.Quantity);
+ target.AddReagent(reagent, quantity);
}
}
diff --git a/Content.Server/Gatherable/GatherableSystem.cs b/Content.Server/Gatherable/GatherableSystem.cs
index b9a375d284..abee3e4549 100644
--- a/Content.Server/Gatherable/GatherableSystem.cs
+++ b/Content.Server/Gatherable/GatherableSystem.cs
@@ -25,25 +25,29 @@ public sealed partial class GatherableSystem : EntitySystem
{
base.Initialize();
+ SubscribeLocalEvent(OnActivate);
SubscribeLocalEvent(OnInteractUsing);
SubscribeLocalEvent(OnDoAfter);
InitializeProjectile();
}
- private void OnInteractUsing(EntityUid uid, GatherableComponent component, InteractUsingEvent args)
+ private void Gather(EntityUid gatheredUid, EntityUid user, EntityUid used, GatheringToolComponent? tool = null, GatherableComponent? component = null)
{
- if (!TryComp(args.Used, out var tool) || component.ToolWhitelist?.IsValid(args.Used) == false)
+ if (!Resolve(used, ref tool, false) || !Resolve(gatheredUid, ref component, false) ||
+ component.ToolWhitelist?.IsValid(used) == false)
+ {
return;
+ }
// Can't gather too many entities at once.
if (tool.MaxGatheringEntities < tool.GatheringEntities.Count + 1)
return;
- var damageRequired = _destructible.DestroyedAt(uid);
+ var damageRequired = _destructible.DestroyedAt(gatheredUid);
var damageTime = (damageRequired / tool.Damage.Total).Float();
damageTime = Math.Max(1f, damageTime);
- var doAfter = new DoAfterArgs(args.User, damageTime, new GatherableDoAfterEvent(), uid, target: uid, used: args.Used)
+ var doAfter = new DoAfterArgs(user, damageTime, new GatherableDoAfterEvent(), gatheredUid, target: gatheredUid, used: used)
{
BreakOnDamage = true,
BreakOnTargetMove = true,
@@ -54,6 +58,16 @@ public sealed partial class GatherableSystem : EntitySystem
_doAfterSystem.TryStartDoAfter(doAfter);
}
+ private void OnActivate(EntityUid uid, GatherableComponent component, ActivateInWorldEvent args)
+ {
+ Gather(uid, args.User, args.User);
+ }
+
+ private void OnInteractUsing(EntityUid uid, GatherableComponent component, InteractUsingEvent args)
+ {
+ Gather(uid, args.User, args.Used, component: component);
+ }
+
private void OnDoAfter(EntityUid uid, GatherableComponent component, GatherableDoAfterEvent args)
{
if(!TryComp(args.Args.Used, out var tool))
diff --git a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs
index 4544bf65fa..d68fac2509 100644
--- a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs
+++ b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs
@@ -1,5 +1,6 @@
using System.Linq;
using Content.Shared.Dataset;
+using Content.Shared.FixedPoint;
using Robust.Shared.Random;
namespace Content.Shared.Random.Helpers
@@ -75,5 +76,61 @@ namespace Content.Shared.Random.Helpers
throw new InvalidOperationException($"Invalid weighted pick");
}
+
+ public static (string reagent, FixedPoint2 quantity) Pick(this WeightedRandomFillSolutionPrototype prototype, IRobustRandom? random = null)
+ {
+ var randomFill = prototype.PickRandomFill(random);
+
+ IoCManager.Resolve(ref random);
+
+ var sum = randomFill.Reagents.Count;
+ var accumulated = 0f;
+
+ var rand = random.NextFloat() * sum;
+
+ foreach (var reagent in randomFill.Reagents)
+ {
+ accumulated += 1f;
+
+ if (accumulated >= rand)
+ {
+ return (reagent, randomFill.Quantity);
+ }
+ }
+
+ // Shouldn't happen
+ throw new InvalidOperationException($"Invalid weighted pick for {prototype.ID}!");
+ }
+
+ public static RandomFillSolution PickRandomFill(this WeightedRandomFillSolutionPrototype prototype, IRobustRandom? random = null)
+ {
+ IoCManager.Resolve(ref random);
+
+ var fills = prototype.Fills;
+ Dictionary picks = new();
+
+ foreach (var fill in fills)
+ {
+ picks[fill] = fill.Weight;
+ }
+
+ var sum = picks.Values.Sum();
+ var accumulated = 0f;
+
+ var rand = random.NextFloat() * sum;
+
+ foreach (var (randSolution, weight) in picks)
+ {
+ accumulated += weight;
+
+ if (accumulated >= rand)
+ {
+ return randSolution;
+ }
+ }
+
+ // Shouldn't happen
+ throw new InvalidOperationException($"Invalid weighted pick for {prototype.ID}!");
+ }
}
}
diff --git a/Content.Shared/Random/RandomFillSolution.cs b/Content.Shared/Random/RandomFillSolution.cs
new file mode 100644
index 0000000000..acbd97db87
--- /dev/null
+++ b/Content.Shared/Random/RandomFillSolution.cs
@@ -0,0 +1,33 @@
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Serialization;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
+
+namespace Content.Shared.Random;
+
+///
+/// Data that specifies reagents that share the same weight and quantity for use with WeightedRandomSolution.
+///
+[Serializable, NetSerializable]
+[DataDefinition]
+public sealed class RandomFillSolution
+{
+ ///
+ /// Quantity of listed reagents.
+ ///
+ [DataField("quantity")]
+ public FixedPoint2 Quantity = 0;
+
+ ///
+ /// Random weight of listed reagents.
+ ///
+ [DataField("weight")]
+ public float Weight = 0;
+
+ ///
+ /// Listed reagents that the weight and quantity apply to.
+ ///
+ [DataField("reagents", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer))]
+ public List Reagents = new();
+}
diff --git a/Content.Shared/Random/WeightedRandomFillSolutionPrototype.cs b/Content.Shared/Random/WeightedRandomFillSolutionPrototype.cs
new file mode 100644
index 0000000000..8a6f133d09
--- /dev/null
+++ b/Content.Shared/Random/WeightedRandomFillSolutionPrototype.cs
@@ -0,0 +1,18 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Random;
+
+///
+/// Random weighting dataset for solutions, able to specify reagents quantity.
+///
+[Prototype("weightedRandomFillSolution")]
+public sealed class WeightedRandomFillSolutionPrototype : IPrototype
+{
+ [IdDataField] public string ID { get; } = default!;
+
+ ///
+ /// List of RandomFills that can be picked from.
+ ///
+ [DataField("fills", required: true)]
+ public List Fills = new();
+}
diff --git a/Resources/Locale/en-US/flavors/flavor-profiles.ftl b/Resources/Locale/en-US/flavors/flavor-profiles.ftl
index 54e763ae6c..ebf341ed18 100644
--- a/Resources/Locale/en-US/flavors/flavor-profiles.ftl
+++ b/Resources/Locale/en-US/flavors/flavor-profiles.ftl
@@ -42,6 +42,7 @@ flavor-base-cheap = cheap
flavor-base-piquant = piquant
flavor-base-sharp = sharp
flavor-base-syrupy = syrupy
+flavor-base-spaceshroom = mysterious
# lmao
flavor-base-terrible = terrible
@@ -145,6 +146,7 @@ flavor-complex-electrons = like electrons
flavor-complex-parents = like someone's parents
flavor-complex-plastic = like plastic
flavor-complex-glue = like glue
+flavor-complex-spaceshroom-cooked = like space umami
# Drink-specific flavors.
diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml
index 8f0f576dfd..c1a1d13500 100644
--- a/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml
+++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml
@@ -131,3 +131,20 @@
- ClothingEyesBlindfold
chance: 0.6
offset: 0.0
+
+- type: entity
+ name: Maint Loot Spawner
+ suffix: Plants
+ id: MaintenancePlantSpawner
+ parent: MarkerBase
+ components:
+ - type: Sprite
+ layers:
+ - state: red
+ - sprite: Objects/Misc/spaceshroom.rsi
+ state: spaceshroom
+ - type: RandomSpawner
+ prototypes:
+ - FoodSpaceshroom
+ chance: 0.6
+ offset: 0.0
diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml
index ebbd76d7a5..1746e091e5 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/base.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml
@@ -34,6 +34,10 @@
- type: Polymorphable
- type: Identity
- type: Hands
+ - type: GatheringTool
+ damage:
+ types:
+ Structural: 50
- type: MovementSpeedModifier
- type: MovedByPressure
- type: Barotrauma
diff --git a/Resources/Prototypes/Entities/Objects/Misc/spaceshroom.yml b/Resources/Prototypes/Entities/Objects/Misc/spaceshroom.yml
new file mode 100644
index 0000000000..9ec6ce0ed1
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Misc/spaceshroom.yml
@@ -0,0 +1,123 @@
+- type: entity
+ name: spaceshroom
+ parent: BaseStructure
+ id: Spaceshroom
+ suffix: Structure
+ description: A cluster of wild mushrooms that likes to grow in dark, moist environments.
+ components:
+ - type: Sprite
+ sprite: Objects/Misc/spaceshroom.rsi
+ state: structure
+ - type: Transform
+ anchored: true
+ - type: Physics
+ bodyType: Static
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeCircle
+ radius: 0.2
+ - type: InteractionOutline
+ # TODO: Nuke this shit
+ - type: OreVein
+ oreChance: 1.0
+ currentOre: SpaceShrooms
+ - type: Gatherable
+ whitelist:
+ components:
+ - Hands
+ - type: Damageable
+ damageContainer: Inorganic
+ damageModifierSet: Wood
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 150
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+
+- type: entity
+ name: spaceshroom
+ parent: FoodProduceBase
+ id: FoodSpaceshroom
+ description: A wild mushroom. There's no telling what effect it could have...
+ components:
+ - type: Produce
+ - type: Sprite
+ sprite: Objects/Misc/spaceshroom.rsi
+ state: object
+ - type: FlavorProfile
+ flavors:
+ - spaceshroom
+ - type: Extractable
+ juiceSolution:
+ reagents:
+ - ReagentId: SpaceDrugs
+ Quantity: 10
+ - type: SolutionContainerManager
+ solutions:
+ food:
+ maxVol: 20
+ reagents:
+ - ReagentId: Nutriment
+ Quantity: 3
+ - ReagentId: Vitamin
+ Quantity: 2
+ - type: RandomFillSolution
+ solution: food
+ weightedRandomId: RandomFillSpaceshroom
+ - type: StaticPrice
+ price: 20
+
+- type: weightedRandomFillSolution
+ id: RandomFillSpaceshroom
+ fills:
+ - quantity: 10
+ weight: 10
+ reagents:
+ - SpaceDrugs
+ - quantity: 0
+ weight: 5
+ reagents:
+ - Water
+ - quantity: 10
+ weight: 3
+ reagents:
+ - Ephedrine
+ - quantity: 10
+ weight: 1
+ reagents:
+ - Lexorin
+ - quantity: 15
+ weight: 1
+ reagents:
+ - Amatoxin
+
+# Cooked Object
+- type: entity
+ name: cooked spaceshroom
+ parent: FoodProduceBase
+ id: FoodSpaceshroomCooked
+ description: A wild mushroom that has been cooked through. It seems the heat has removed its chemical effects.
+ components:
+ - type: FlavorProfile
+ flavors:
+ - spaceshroomcooked
+ - type: SolutionContainerManager
+ solutions:
+ food:
+ maxVol: 15
+ reagents:
+ - ReagentId: Nutriment
+ Quantity: 10
+ - ReagentId: Vitamin
+ Quantity: 5
+ - type: Sprite
+ sprite: Objects/Misc/spaceshroom.rsi
+ state: spaceshroom_cooked
+ - type: Produce
+ - type: StaticPrice
+ price: 40
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/randompill.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/randompill.yml
index 14bc13343b..fcd738f0db 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Medical/randompill.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/randompill.yml
@@ -1,38 +1,46 @@
-- type: weightedRandom
+- type: weightedRandomFillSolution
id: RandomFillStrangePill
- weights:
- # Elements
- Aluminium: 1
- Carbon: 1
- Chlorine: 1
- Copper: 1
- Fluorine: 1
- Hydrogen: 1
- Iodine: 1
- Lithium: 1
- Mercury: 1
- Potassium: 1
- Phosphorus: 1
- Radium: 1
- Silicon: 1
- Sulfur: 1
- Sodium: 1
- # Medicines
- Ipecac: 3
- Omnizine: 2
- Tricordrazine: 3
- # Narcotics
- Desoxyephedrine: 3
- Ephedrine: 3
- SpaceDrugs: 5
- Nocturine: 3
- MuteToxin: 3
- NorepinephricAcid: 3
- # Toxins
- ChloralHydrate: 3
- Mold: 3
- Pax: 3
- Toxin: 5
+ fills:
+ - quantity: 20
+ weight: 1
+ reagents:
+ - Aluminium
+ - Carbon
+ - Chlorine
+ - Copper
+ - Fluorine
+ - Hydrogen
+ - Iodine
+ - Lithium
+ - Mercury
+ - Potassium
+ - Phosphorus
+ - Radium
+ - Silicon
+ - Sulfur
+ - Sodium
+ - quantity: 20
+ weight: 2
+ reagents:
+ - Omnizine
+ - quantity: 20
+ weight: 3
+ reagents:
+ - ChloralHydrate
+ - Desoxyephedrine
+ - Ephedrine
+ - Ipecac
+ - Mold
+ - MuteToxin
+ - Nocturine
+ - NorepinephricAcid
+ - Pax
+ - Tricordrazine
+ - quantity: 20
+ weight: 5
+ reagents:
+ - SpaceDrugs
+ - Toxin
- type: entity
name: strange pill
@@ -47,7 +55,6 @@
- type: RandomFillSolution
solution: food
weightedRandomId: RandomFillStrangePill
- quantity: 20
- type: Sprite
sprite: Objects/Specific/Chemistry/pills.rsi
layers:
diff --git a/Resources/Prototypes/Flavors/flavors.yml b/Resources/Prototypes/Flavors/flavors.yml
index 7e61b24334..ab82a13fcb 100644
--- a/Resources/Prototypes/Flavors/flavors.yml
+++ b/Resources/Prototypes/Flavors/flavors.yml
@@ -823,3 +823,13 @@
id: rocksandstones
flavorType: Complex
description: flavor-complex-rocksandstones
+
+- type: flavor
+ id: spaceshroom
+ flavorType: Base
+ description: flavor-base-spaceshroom
+
+- type: flavor
+ id: spaceshroomcooked
+ flavorType: Complex
+ description: flavor-complex-spaceshroom-cooked
\ No newline at end of file
diff --git a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml
index 2cb601ccd7..0b26f65dcc 100644
--- a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml
+++ b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml
@@ -1632,3 +1632,11 @@
solids:
FoodChevreSlice: 1
FoodBreadBaguetteSlice: 1
+
+- type: microwaveMealRecipe
+ id: RecipeCookedSpaceshroom
+ name: cooked spaceshroom recipe
+ result: FoodSpaceshroomCooked
+ time: 5
+ solids:
+ FoodSpaceshroom: 1
\ No newline at end of file
diff --git a/Resources/Prototypes/ore.yml b/Resources/Prototypes/ore.yml
index 33f17a5e01..b17e0839a2 100644
--- a/Resources/Prototypes/ore.yml
+++ b/Resources/Prototypes/ore.yml
@@ -1,3 +1,10 @@
+# TODO: Kill ore veins
+# Split it into 2 components, 1 for "spawn XYZ on destruction" and 1 for "randomly select one of these for spawn on destruction"
+# You could even just use an entityspawncollection instead.
+- type: ore
+ id: SpaceShrooms
+ oreEntity: FoodSpaceshroom
+
# High yields
- type: ore
id: OreSteel
diff --git a/Resources/Textures/Objects/Misc/spaceshroom.rsi/meta.json b/Resources/Textures/Objects/Misc/spaceshroom.rsi/meta.json
new file mode 100644
index 0000000000..46d9ba04e4
--- /dev/null
+++ b/Resources/Textures/Objects/Misc/spaceshroom.rsi/meta.json
@@ -0,0 +1,20 @@
+{
+ "version": 1,
+ "license": "CC0-1.0",
+ "copyright": "Created by @UbaserB (GitHub)",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "object"
+ },
+ {
+ "name": "spaceshroom_cooked"
+ },
+ {
+ "name": "structure"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/Objects/Misc/spaceshroom.rsi/object.png b/Resources/Textures/Objects/Misc/spaceshroom.rsi/object.png
new file mode 100644
index 0000000000..6a5b84993d
Binary files /dev/null and b/Resources/Textures/Objects/Misc/spaceshroom.rsi/object.png differ
diff --git a/Resources/Textures/Objects/Misc/spaceshroom.rsi/spaceshroom_cooked.png b/Resources/Textures/Objects/Misc/spaceshroom.rsi/spaceshroom_cooked.png
new file mode 100644
index 0000000000..633d4a2675
Binary files /dev/null and b/Resources/Textures/Objects/Misc/spaceshroom.rsi/spaceshroom_cooked.png differ
diff --git a/Resources/Textures/Objects/Misc/spaceshroom.rsi/structure.png b/Resources/Textures/Objects/Misc/spaceshroom.rsi/structure.png
new file mode 100644
index 0000000000..c23bed8ee0
Binary files /dev/null and b/Resources/Textures/Objects/Misc/spaceshroom.rsi/structure.png differ