--- /dev/null
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Construction;
+using Content.Shared.Examine;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Construction.Conditions;
+
+/// <summary>
+/// Requires that a certain solution has a minimum amount of a reagent to proceed.
+/// </summary>
+[DataDefinition]
+public sealed partial class MinSolution : IGraphCondition
+{
+ /// <summary>
+ /// The solution that needs to have the reagent.
+ /// </summary>
+ [DataField(required: true)]
+ public string Solution = string.Empty;
+
+ /// <summary>
+ /// The reagent that needs to be present.
+ /// </summary>
+ [DataField(required: true)]
+ public ReagentId Reagent = new();
+
+ /// <summary>
+ /// How much of the reagent must be present.
+ /// </summary>
+ [DataField]
+ public FixedPoint2 Quantity = 1;
+
+ public bool Condition(EntityUid uid, IEntityManager entMan)
+ {
+ var containerSys = entMan.System<SolutionContainerSystem>();
+ if (!containerSys.TryGetSolution(uid, Solution, out var solution))
+ return false;
+
+ solution.TryGetReagentQuantity(Reagent, out var quantity);
+ return quantity >= Quantity;
+ }
+
+ public bool DoExamine(ExaminedEvent args)
+ {
+ var entMan = IoCManager.Resolve<IEntityManager>();
+ var uid = args.Examined;
+
+ var containerSys = entMan.System<SolutionContainerSystem>();
+ if (!containerSys.TryGetSolution(uid, Solution, out var solution))
+ return false;
+
+ solution.TryGetReagentQuantity(Reagent, out var quantity);
+
+ // already has enough so dont show examine
+ if (quantity >= Quantity)
+ return false;
+
+ args.PushMarkup(Loc.GetString("construction-examine-condition-min-solution",
+ ("quantity", Quantity - quantity), ("reagent", Name())) + "\n");
+ return true;
+ }
+
+ public IEnumerable<ConstructionGuideEntry> GenerateGuideEntry()
+ {
+ yield return new ConstructionGuideEntry()
+ {
+ Localization = "construction-guide-condition-min-solution",
+ Arguments = new (string, object)[]
+ {
+ ("quantity", Quantity),
+ ("reagent", Name())
+ }
+ };
+ }
+
+ private string Name()
+ {
+ var protoMan = IoCManager.Resolve<IPrototypeManager>();
+ var proto = protoMan.Index<ReagentPrototype>(Reagent.Prototype);
+ return proto.LocalizedName;
+ }
+}
--- /dev/null
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Construction;
+using Content.Shared.Examine;
+
+namespace Content.Server.Construction.Conditions;
+
+/// <summary>
+/// Requires that a certain solution be empty to proceed.
+/// </summary>
+[DataDefinition]
+public sealed partial class SolutionEmpty : IGraphCondition
+{
+ /// <summary>
+ /// The solution that needs to be empty.
+ /// </summary>
+ [DataField]
+ public string Solution;
+
+ public bool Condition(EntityUid uid, IEntityManager entMan)
+ {
+ var containerSys = entMan.System<SolutionContainerSystem>();
+ if (!containerSys.TryGetSolution(uid, Solution, out var solution))
+ return false;
+
+ return solution.Volume == 0;
+ }
+
+ public bool DoExamine(ExaminedEvent args)
+ {
+ var entMan = IoCManager.Resolve<IEntityManager>();
+ var uid = args.Examined;
+
+ var containerSys = entMan.System<SolutionContainerSystem>();
+ if (!containerSys.TryGetSolution(uid, Solution, out var solution))
+ return false;
+
+ // already empty so dont show examine
+ if (solution.Volume == 0)
+ return false;
+
+ args.PushMarkup(Loc.GetString("construction-examine-condition-solution-empty"));
+ return true;
+ }
+
+ public IEnumerable<ConstructionGuideEntry> GenerateGuideEntry()
+ {
+ yield return new ConstructionGuideEntry()
+ {
+ Localization = "construction-guide-condition-solution-empty"
+ };
+ }
+}
--- /dev/null
+construction-examine-condition-min-solution = First, add {$quantity}u of {$reagent}.
+construction-guide-condition-min-solution = Add {$quantity}u of {$reagent}
--- /dev/null
+# SolutionEmpty
+construction-examine-condition-solution-empty = First, empty the contents.
+construction-guide-condition-solution-empty = Empty the contents.
- type: PhysicalComposition
materialComposition:
Steel: 50 #reduce, reuse, recycle
+ - type: Tag
+ tags:
+ - DrinkCan
- type: entity
parent: DrinkCanBaseFull
- type: Tag
tags:
- Cola
+ - DrinkCan
- Recyclable
- type: Sprite
sprite: Objects/Consumable/Drinks/cola.rsi
- type: Item
sprite: Objects/Consumable/Drinks/cola.rsi
+# created when taking apart an ied
+- type: entity
+ parent: DrinkColaCan
+ id: DrinkColaCanEmpty
+ suffix: empty
+ components:
+ - type: SolutionContainerManager
+ solutions:
+ drink:
+ maxVol: 30
+ - type: Openable
+ opened: true
+ - type: Sprite
+ sprite: Objects/Consumable/Drinks/cola.rsi
+ layers:
+ - state: icon_open
+ - type: Item
+ sprite: Objects/Consumable/Drinks/cola.rsi
+ - type: Tag
+ tags:
+ - Cola
+ - DrinkCan
+ - Recyclable
+ - Trash
+
- type: entity
parent: DrinkCanBaseFull
id: DrinkIcedTeaCan
Quantity: 5
- type: Tag
tags:
+ - DrinkCan
- Recyclable
- type: Sprite
sprite: Objects/Consumable/Drinks/robustnukie.rsi
--- /dev/null
+# ied crafted from random stuff
+# ideally it would be dynamic and work by actually sparking the solution but that doesnt exist yet :(
+# with that you could make napalm ied instead of welding fuel with no additional complexity
+- type: entity
+ parent: BaseItem
+ id: ImprovisedExplosive
+ name: improvised explosive device
+ description: A weak, improvised incendiary device.
+ components:
+ - type: Sprite
+ sprite: Objects/Weapons/Bombs/ied.rsi
+ layers:
+ - state: base
+ - state: fuel
+ - state: wires
+ - type: Item
+ sprite: Objects/Consumable/Drinks/cola.rsi
+ - type: OnUseTimerTrigger
+ delay: 5
+ examinable: false
+ initialBeepDelay: 0
+ beepSound: /Audio/Effects/lightburn.ogg
+ # TODO: random timer when crafted
+ - type: TriggerOnSignal
+ - type: DeviceLinkSink
+ ports:
+ - Trigger
+ - type: Explosive # Weak explosion in a very small radius. Doesn't break underplating.
+ explosionType: Default
+ totalIntensity: 50
+ intensitySlope: 5
+ maxIntensity: 6
+ canCreateVacuum: false
+ - type: ExplodeOnTrigger
+ - type: Damageable
+ damageContainer: Inorganic
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 50
+ behaviors:
+ - !type:DoActsBehavior
+ acts: ["Destruction"]
+ - !type:ExplodeBehavior
+ - type: Construction
+ graph: ImprovisedExplosive
+ node: ied
+
+# has igniter but no fuel or wires
+- type: entity
+ parent: DrinkColaCanEmpty
+ id: ImprovisedExplosiveEmpty
+ name: improvised explosive device
+ suffix: empty
+ description: A weak, improvised incendiary device. This one has no fuel.
+ components:
+ - type: Sprite
+ sprite: Objects/Weapons/Bombs/ied.rsi
+ layers:
+ - state: base
+ map: ["enum.OpenableVisuals.Layer"]
+ # bad dog
+ - type: GenericVisualizer
+ visuals:
+ enum.OpenableVisuals.Opened:
+ enum.OpenableVisuals.Layer:
+ True: {state: "base"}
+ False: {state: "base"}
+ - type: Construction
+ graph: ImprovisedExplosive
+ node: empty
+ defaultTarget: ied
+ - type: Tag
+ tags:
+ - Trash
+ # no DrinkCan, prevent using it to make another ied
+
+- type: entity
+ parent: ImprovisedExplosiveEmpty
+ id: ImprovisedExplosiveFuel
+ suffix: fuel
+ description: A weak, improvised incendiary device. This one is missing wires.
+ components:
+ - type: Sprite
+ layers:
+ - state: base
+ map: ["enum.OpenableVisuals.Layer"]
+ - state: fuel
+ - type: SolutionContainerManager
+ solutions:
+ drink:
+ maxVol: 30
+ reagents:
+ - ReagentId: WeldingFuel
+ Quantity: 30
+ - type: Construction
+ node: fuel
+ defaultTarget: ied
+ - type: Tag
+ tags: []
--- /dev/null
+- type: constructionGraph
+ id: ImprovisedExplosive
+ start: start
+ graph:
+ - node: start
+ edges:
+ - to: empty
+ steps:
+ - tag: DrinkCan
+ name: an empty can
+ icon:
+ sprite: Objects/Consumable/Drinks/cola.rsi
+ state: icon_open
+ doAfter: 1
+ - tag: Igniter
+ name: an igniter
+ icon:
+ sprite: Objects/Devices/igniter.rsi
+ state: icon
+ doAfter: 1
+ - node: empty
+ entity: ImprovisedExplosiveEmpty
+ edges:
+ - to: start
+ completed:
+ - !type:SpawnPrototype
+ prototype: DrinkColaCanEmpty
+ - !type:SpawnPrototype
+ prototype: Igniter
+ - !type:DeleteEntity {}
+ steps:
+ - tool: Prying
+ doAfter: 1
+ - to: fuel
+ conditions:
+ - !type:MinSolution
+ solution: drink
+ reagent:
+ ReagentId: WeldingFuel
+ quantity: 30
+ steps:
+ - tool: Screwing
+ doAfter: 1
+ - node: fuel
+ entity: ImprovisedExplosiveFuel
+ edges:
+ - to: empty
+ conditions:
+ - !type:SolutionEmpty
+ solution: drink
+ steps:
+ - tool: Screwing
+ doAfter: 1
+ - to: ied
+ conditions: # no dumping out 29u of the fuel then adding wires :)
+ - !type:MinSolution
+ solution: drink
+ reagent:
+ ReagentId: WeldingFuel
+ quantity: 30
+ steps:
+ - material: Cable
+ amount: 5
+ doAfter: 2
+ - node: ied
+ entity: ImprovisedExplosive
+ edges:
+ - to: fuel
+ completed:
+ - !type:SpawnPrototype
+ prototype: CableApcStack1
+ amount: 5
+ steps:
+ - tool: Cutting
+ doAfter: 2
icon:
sprite: Objects/Misc/rifle_stock.rsi
state: icon
+
+- type: construction
+ name: improvised explosive device
+ id: improvisedexplosive
+ graph: ImprovisedExplosive
+ startNode: start
+ targetNode: ied
+ category: construction-category-weapons
+ objectType: Item
+ description: A weak, improvised incendiary device.
+ icon:
+ sprite: Objects/Weapons/Bombs/ied.rsi
+ state: icon
- type: Tag
id: Donut
+- type: Tag
+ id: DrinkCan
+
- type: Tag
id: DrinkSpaceGlue
--- /dev/null
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Created by deltanedas (github) for SS14, icon and base based on cola sprite from cev-eris",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "base"
+ },
+ {
+ "name": "fuel"
+ },
+ {
+ "name": "wires"
+ }
+ ]
+}