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" + } + ] +}