From: iller_saver <55444968+illersaver@users.noreply.github.com>
Date: Mon, 1 May 2023 14:34:11 +0000 (+0300)
Subject: New smokable: Vape! (#13072)
X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=369bdcc3d18f275c083093898ccdf45c04c7b4bc;p=space-station-14.git
New smokable: Vape! (#13072)
---
diff --git a/Content.Server/Nutrition/Components/VapeComponent.cs b/Content.Server/Nutrition/Components/VapeComponent.cs
new file mode 100644
index 0000000000..28b2e6e531
--- /dev/null
+++ b/Content.Server/Nutrition/Components/VapeComponent.cs
@@ -0,0 +1,51 @@
+using System.Threading;
+using Content.Server.Nutrition.EntitySystems;
+using Content.Shared.Damage;
+using Content.Shared.Atmos;
+
+///
+/// Component for vapes
+///
+namespace Content.Server.Nutrition.Components
+{
+ [RegisterComponent, Access(typeof(SmokingSystem))]
+ public sealed class VapeComponent : Component
+ {
+ [DataField("delay")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float Delay { get; set; } = 5;
+
+ [DataField("userDelay")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float UserDelay { get; set; } = 2;
+
+ [DataField("explosionIntensity")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float ExplosionIntensity { get; set; } = 2.5f;
+
+ [DataField("explodeOnUse")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool ExplodeOnUse { get; set; } = false;
+
+ [DataField("damage", required: true)]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public DamageSpecifier Damage = default!;
+
+ [DataField("gasType")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public Gas GasType { get; set; } = Gas.WaterVapor;
+
+ ///
+ /// Solution volume will be divided by this number and converted to the gas
+ ///
+ [DataField("reductionFactor")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float ReductionFactor { get; set; } = 300f;
+
+ [DataField("solutionNeeded")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public string SolutionNeeded = "Water";
+
+ public CancellationTokenSource? CancelToken;
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs
new file mode 100644
index 0000000000..15661568f6
--- /dev/null
+++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs
@@ -0,0 +1,169 @@
+using Content.Server.Nutrition.Components;
+using Content.Server.Body.Components;
+using Content.Shared.Interaction;
+using Content.Server.DoAfter;
+using System.Threading;
+using Content.Server.Explosion.EntitySystems;
+using Content.Shared.Damage;
+using Content.Server.Popups;
+using Content.Shared.IdentityManagement;
+using Content.Shared.DoAfter;
+using Content.Shared.Emag.Systems;
+using Content.Shared.Emag.Components;
+using Content.Shared.Nutrition;
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.Atmos;
+
+///
+/// System for vapes
+///
+namespace Content.Server.Nutrition.EntitySystems
+{
+ public sealed partial class SmokingSystem
+ {
+ [Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
+ [Dependency] private readonly DamageableSystem _damageableSystem = default!;
+ [Dependency] private readonly FoodSystem _foodSystem = default!;
+ [Dependency] private readonly ExplosionSystem _explosionSystem = default!;
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
+ private void InitializeVapes()
+ {
+ SubscribeLocalEvent(OnVapeInteraction);
+ SubscribeLocalEvent(OnVapeDoAfter);
+ SubscribeLocalEvent(OnEmagged);
+ }
+
+ private void OnVapeInteraction(EntityUid uid, VapeComponent comp, AfterInteractEvent args)
+ {
+ _solutionContainerSystem.TryGetRefillableSolution(uid, out var solution);
+
+ var delay = comp.Delay;
+ var forced = true;
+ var exploded = false;
+
+ if (!args.CanReach
+ || solution == null
+ || comp.CancelToken != null
+ || !TryComp(args.Target, out var _)
+ || _foodSystem.IsMouthBlocked(args.Target.Value, args.User))
+ return;
+
+ if (args.Target == args.User)
+ {
+ delay = comp.UserDelay;
+ forced = false;
+ }
+
+ if (comp.ExplodeOnUse || HasComp(uid))
+ {
+ _explosionSystem.QueueExplosion(uid, "Default", comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false);
+ EntityManager.DeleteEntity(uid);
+ exploded = true;
+ }
+ else
+ {
+ foreach (var name in solution.Contents)
+ {
+ if (name.ReagentId != comp.SolutionNeeded)
+ {
+ exploded = true;
+ _explosionSystem.QueueExplosion(uid, "Default", comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false);
+ EntityManager.DeleteEntity(uid);
+ break;
+ }
+ }
+ }
+
+ if (forced)
+ {
+ var targetName = Identity.Entity(args.Target.Value, EntityManager);
+ var userName = Identity.Entity(args.User, EntityManager);
+
+ _popupSystem.PopupEntity(
+ Loc.GetString("vape-component-try-use-vape-forced", ("user", userName)), args.Target.Value,
+ args.Target.Value);
+
+ _popupSystem.PopupEntity(
+ Loc.GetString("vape-component-try-use-vape-forced-user", ("target", targetName)), args.User,
+ args.User);
+ }
+ else
+ {
+ _popupSystem.PopupEntity(
+ Loc.GetString("vape-component-try-use-vape"), args.User,
+ args.User);
+ }
+
+ if (!exploded)
+ {
+ comp.CancelToken = new CancellationTokenSource();
+
+ var vapeDoAfterEvent = new VapeDoAfterEvent(solution, forced);
+ _doAfterSystem.TryStartDoAfter(new DoAfterArgs(args.User, delay, vapeDoAfterEvent, uid, target: args.Target, used: uid)
+ {
+ BreakOnTargetMove = true,
+ BreakOnUserMove = false,
+ BreakOnDamage = true
+ });
+ }
+ args.Handled = true;
+ }
+
+ private void OnVapeDoAfter(EntityUid uid, VapeComponent comp, VapeDoAfterEvent args)
+ {
+ if (args.Cancelled)
+ {
+ comp.CancelToken = null;
+ return;
+ }
+
+ comp.CancelToken = null;
+
+ if (args.Handled
+ || args.Args.Target == null)
+ return;
+
+ var environment = _atmosphereSystem.GetContainingMixture(args.Args.Target.Value, true, true);
+ if (environment == null)
+ {
+ return;
+ }
+
+ //Smoking kills(your lungs, but there is no organ damage yet)
+ _damageableSystem.TryChangeDamage(args.Args.Target.Value, comp.Damage, true);
+
+ var merger = new GasMixture(1) { Temperature = args.Solution.Temperature};
+ merger.SetMoles(comp.GasType, args.Solution.Volume.Value / comp.ReductionFactor);
+
+ _atmosphereSystem.Merge(environment, merger);
+
+ args.Solution.RemoveAllSolution();
+
+ if (args.Forced)
+ {
+ var targetName = Identity.Entity(args.Args.Target.Value, EntityManager);
+ var userName = Identity.Entity(args.Args.User, EntityManager);
+
+ _popupSystem.PopupEntity(
+ Loc.GetString("vape-component-vape-success-forced", ("user", userName)), args.Args.Target.Value,
+ args.Args.Target.Value);
+
+ _popupSystem.PopupEntity(
+ Loc.GetString("vape-component-vape-success-user-forced", ("target", targetName)), args.Args.User,
+ args.Args.Target.Value);
+ }
+ else
+ {
+ _popupSystem.PopupEntity(
+ Loc.GetString("vape-component-vape-success"), args.Args.Target.Value,
+ args.Args.Target.Value);
+ }
+ }
+ private void OnEmagged(EntityUid uid, VapeComponent component, ref GotEmaggedEvent args)
+ {
+ args.Handled = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs
index a985f39315..772e872110 100644
--- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs
+++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs
@@ -47,6 +47,7 @@ namespace Content.Server.Nutrition.EntitySystems
InitializeCigars();
InitializePipes();
+ InitializeVapes();
}
public void SetSmokableState(EntityUid uid, SmokableState state, SmokableComponent? smokable = null,
diff --git a/Content.Shared/Nutrition/Events.cs b/Content.Shared/Nutrition/Events.cs
index 3e3bd93470..bf4acfafa2 100644
--- a/Content.Shared/Nutrition/Events.cs
+++ b/Content.Shared/Nutrition/Events.cs
@@ -1,5 +1,6 @@
using Content.Shared.DoAfter;
using Robust.Shared.Serialization;
+using Content.Shared.Chemistry.Components;
namespace Content.Shared.Nutrition;
@@ -27,3 +28,28 @@ public sealed class ConsumeDoAfterEvent : DoAfterEvent
public override DoAfterEvent Clone() => this;
}
+
+///
+/// Do after event for vape.
+///
+[Serializable, NetSerializable]
+public sealed class VapeDoAfterEvent : DoAfterEvent
+{
+ [DataField("solution", required: true)]
+ public readonly Solution Solution = default!;
+
+ [DataField("forced", required: true)]
+ public readonly bool Forced = default!;
+
+ private VapeDoAfterEvent()
+ {
+ }
+
+ public VapeDoAfterEvent(Solution solution, bool forced)
+ {
+ Solution = solution;
+ Forced = forced;
+ }
+
+ public override DoAfterEvent Clone() => this;
+}
diff --git a/Resources/Locale/en-US/nutrition/components/vape-component.ftl b/Resources/Locale/en-US/nutrition/components/vape-component.ftl
new file mode 100644
index 0000000000..2d25e1a8de
--- /dev/null
+++ b/Resources/Locale/en-US/nutrition/components/vape-component.ftl
@@ -0,0 +1,6 @@
+vape-component-vape-success = You puffed on the vape.
+vape-component-vape-success-forced = {CAPITALIZE(THE($user))} forced you to puffon the vape.
+vape-component-vape-success-user-forced = You successfully forced to puff {THE($target)}.
+vape-component-try-use-vape-forced = {CAPITALIZE(THE($user))} is trying to make you puff on the vape.
+vape-component-try-use-vape-forced-user = You are forcing {THE($target)} to puff on the vape.
+vape-component-try-use-vape = You are trying to puff on the vape.
\ No newline at end of file
diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml
index 65d886054a..d5c8738ea7 100644
--- a/Resources/Prototypes/Catalog/Research/technologies.yml
+++ b/Resources/Prototypes/Catalog/Research/technologies.yml
@@ -99,6 +99,7 @@
unlockedRecipes:
- SeedExtractorMachineCircuitboard
- HydroponicsTrayMachineCircuitboard
+ - Vape
- type: technology
name: technologies-virology
diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cigs.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cigs.yml
index df0687b5b4..a7f6dbd76d 100644
--- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cigs.yml
+++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cigs.yml
@@ -7,6 +7,7 @@
CigPackBlack: 2
CigarCase: 1
SmokingPipeFilledTobacco: 1
+ Vape: 1
Matchbox: 5
PackPaperRollingFilters: 3
CheapLighter: 4
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Vapes/vape.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Vapes/vape.yml
new file mode 100644
index 0000000000..bdb7bb23cf
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Vapes/vape.yml
@@ -0,0 +1,10 @@
+- type: entity
+ id: Vape
+ parent: BaseVape
+ name: vape
+ description: "Like a cigar, but for tough teens. (WARNING:Pour only water into the vape)"
+ components:
+ - type: Sprite
+ sprite: Objects/Consumable/Smokeables/Vapes/vape-standart.rsi
+ netsync: false
+ state: icon
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/base_smokeables.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/base_smokeables.yml
index 419ab76391..62af60b66e 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/base_smokeables.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/base_smokeables.yml
@@ -61,3 +61,21 @@
solutions:
smokable:
maxVol: 20
+
+- type: entity
+ parent: BaseItem
+ id: BaseVape
+ abstract: true
+ components:
+ - type: Vape
+ damage:
+ groups:
+ Burn: 2
+ - type: SolutionContainerManager
+ solutions:
+ smokable:
+ maxVol: 10
+ - type: RefillableSolution
+ solution: smokable
+ - type: ExaminableSolution
+ solution: smokable
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index 6a2046dd2d..050f225ef2 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -239,6 +239,7 @@
- ClothingShoesBootsMag
- NodeScanner
- HolofanProjector
+ - Vape
- type: entity
parent: Protolathe
diff --git a/Resources/Prototypes/Recipes/Lathes/chemistry.yml b/Resources/Prototypes/Recipes/Lathes/chemistry.yml
index 3d5807517a..709447bd9b 100644
--- a/Resources/Prototypes/Recipes/Lathes/chemistry.yml
+++ b/Resources/Prototypes/Recipes/Lathes/chemistry.yml
@@ -49,3 +49,14 @@
completetime: 2
materials:
Glass: 50
+
+- type: latheRecipe
+ id: Vape
+ icon:
+ sprite: Objects/Consumable/Smokeables/Vapes/vape-standart.rsi
+ state: icon
+ result: Vape
+ completetime: 2
+ materials:
+ Plastic: 100
+ Steel: 250
diff --git a/Resources/Textures/Objects/Consumable/Smokeables/Vapes/vape-standart.rsi/icon.png b/Resources/Textures/Objects/Consumable/Smokeables/Vapes/vape-standart.rsi/icon.png
new file mode 100644
index 0000000000..0c212d3ca8
Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Smokeables/Vapes/vape-standart.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Consumable/Smokeables/Vapes/vape-standart.rsi/meta.json b/Resources/Textures/Objects/Consumable/Smokeables/Vapes/vape-standart.rsi/meta.json
new file mode 100644
index 0000000000..6b846e691a
--- /dev/null
+++ b/Resources/Textures/Objects/Consumable/Smokeables/Vapes/vape-standart.rsi/meta.json
@@ -0,0 +1,14 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Created by Mozinov",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ }
+ ]
+}