diff --git a/Content.Server/White/Other/RechargeableSystem/RechargeableComponent.cs b/Content.Server/White/Other/RechargeableSystem/RechargeableComponent.cs new file mode 100644 index 0000000000..91da9e8d79 --- /dev/null +++ b/Content.Server/White/Other/RechargeableSystem/RechargeableComponent.cs @@ -0,0 +1,31 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.Audio; + +namespace Content.Server.White.Other.RechargeableSystem; + +[RegisterComponent] +public sealed partial class RechargeableComponent : Component +{ + [DataField("maxCharge")] + [ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2 MaxCharge = FixedPoint2.New(40); + + [DataField("chargePerSecond")] + [ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2 ChargePerSecond = FixedPoint2.New(1); + + [DataField("rechargeDelay")] + [ViewVariables(VVAccess.ReadWrite)] + public float RechargeDelay = 30f; + + [DataField("turnOnFailSound")] + public SoundSpecifier TurnOnFailSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/button.ogg"); + + [ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2 Charge; + + [ViewVariables] + public bool Discharged; + + public float AccumulatedFrametime; +} diff --git a/Content.Server/White/Other/RechargeableSystem/RechargeableSystem.cs b/Content.Server/White/Other/RechargeableSystem/RechargeableSystem.cs new file mode 100644 index 0000000000..6daa879c2e --- /dev/null +++ b/Content.Server/White/Other/RechargeableSystem/RechargeableSystem.cs @@ -0,0 +1,105 @@ +using Content.Server.Item; +using Content.Server.Popups; +using Content.Shared.Damage; +using Content.Shared.Examine; +using Content.Shared.FixedPoint; +using Content.Shared.Item.ItemToggle.Components; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; + +namespace Content.Server.White.Other.RechargeableSystem; + + +public sealed class RechargeableSystem : EntitySystem +{ + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly ItemToggleSystem _itemToggle = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnDamageChanged); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnTryActivate); + } + + private void OnTryActivate(Entity ent, ref ItemToggleActivateAttemptEvent args) + { + if (!ent.Comp.Discharged) + return; + + args.Cancelled = true; + + _audio.PlayPvs(_audio.GetSound(ent.Comp.TurnOnFailSound), ent, AudioParams.Default.WithVariation(0.25f)); + _popup.PopupEntity(Loc.GetString("stunbaton-component-low-charge"), args.User ?? ent); + } + + private void OnExamined(EntityUid uid, RechargeableComponent component, ExaminedEvent args) + { + if (component.Discharged) + { + var remainingTime = (int) (component.RechargeDelay - component.AccumulatedFrametime); + args.PushMarkup("Он [color=red]разряжен[/color]."); + args.PushMarkup($"Осталось времени для зарядки: [color=green]{remainingTime}[/color] секунд."); + return; + } + + var currentCharge = (int) (100 * component.Charge / component.MaxCharge); + args.PushMarkup($"Текущий заряд: [color=green]{currentCharge}%[/color]"); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var rechargeable in EntityManager.EntityQuery()) + { + if (!rechargeable.Discharged && rechargeable.Charge == rechargeable.MaxCharge) + continue; + + rechargeable.AccumulatedFrametime += frameTime; + + var delay = rechargeable.Discharged ? rechargeable.RechargeDelay : 1f; + + if (rechargeable.AccumulatedFrametime < delay) + continue; + + rechargeable.AccumulatedFrametime -= delay; + + if (rechargeable.Discharged) + { + rechargeable.Discharged = false; + rechargeable.Charge = rechargeable.MaxCharge; + } + else + { + rechargeable.Charge = FixedPoint2.Min(rechargeable.MaxCharge, + rechargeable.Charge + rechargeable.ChargePerSecond); + } + } + } + + private void OnDamageChanged(EntityUid uid, RechargeableComponent component, DamageChangedEvent args) + { + if (component.Discharged || args.DamageDelta == null) + return; + + var totalDamage = args.DamageDelta.GetTotal(); + + component.Charge = FixedPoint2.Max(FixedPoint2.Zero, component.Charge - totalDamage); + + if (component.Charge > FixedPoint2.Zero) + return; + + component.Discharged = true; + _itemToggle.TryDeactivate(uid); + } + + private void OnInit(EntityUid uid, RechargeableComponent component, ComponentInit args) + { + component.Charge = component.MaxCharge; + } +} diff --git a/Content.Shared/Weapons/Reflect/ReflectComponent.cs b/Content.Shared/Weapons/Reflect/ReflectComponent.cs index 8e7b8975d9..2276447e8d 100644 --- a/Content.Shared/Weapons/Reflect/ReflectComponent.cs +++ b/Content.Shared/Weapons/Reflect/ReflectComponent.cs @@ -32,6 +32,11 @@ public sealed partial class ReflectComponent : Component [DataField("soundOnReflect")] public SoundSpecifier? SoundOnReflect = new SoundPathSpecifier("/Audio/Weapons/Guns/Hits/laser_sear_wall.ogg"); + + // WD START + [DataField("damageOnReflect"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public bool DamageOnReflect; + // WD END } [Flags] diff --git a/Content.Shared/Weapons/Reflect/ReflectSystem.cs b/Content.Shared/Weapons/Reflect/ReflectSystem.cs index 4a7c2f6b6a..fad3a2d2f9 100644 --- a/Content.Shared/Weapons/Reflect/ReflectSystem.cs +++ b/Content.Shared/Weapons/Reflect/ReflectSystem.cs @@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using Content.Shared.Administration.Logs; using Content.Shared.Audio; +using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Hands; using Content.Shared.Inventory; @@ -35,6 +36,7 @@ public sealed class ReflectSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; public override void Initialize() { @@ -123,6 +125,12 @@ public sealed class ReflectSystem : EntitySystem if (Resolve(projectile, ref projectileComp, false)) { + if (reflect.DamageOnReflect) // WD + { + _damageableSystem.TryChangeDamage(reflector, projectileComp.Damage, projectileComp.IgnoreResistances, + origin: projectileComp.Shooter); + } + _adminLogger.Add(LogType.BulletHit, LogImpact.Medium, $"{ToPrettyString(user)} reflected {ToPrettyString(projectile)} from {ToPrettyString(projectileComp.Weapon)} shot by {projectileComp.Shooter}"); projectileComp.Shooter = user; diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 198cae1966..5c101d42fc 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -1366,7 +1366,7 @@ icon: { sprite: /Textures/Objects/Weapons/Melee/e_shield.rsi, state: eshield-on } productEntity: EnergyShield cost: - Telecrystal: 5 + Telecrystal: 6 categories: - UplinkMisc saleLimit: 1 diff --git a/Resources/Prototypes/Entities/Objects/Shields/shields.yml b/Resources/Prototypes/Entities/Objects/Shields/shields.yml index 3006cd1753..41ac60bc14 100644 --- a/Resources/Prototypes/Entities/Objects/Shields/shields.yml +++ b/Resources/Prototypes/Entities/Objects/Shields/shields.yml @@ -364,9 +364,14 @@ path: /Audio/Weapons/ebladeon.ogg soundDeactivate: path: /Audio/Weapons/ebladeoff.ogg - - type: ItemToggleActiveSound - activeSound: - path: /Audio/Weapons/ebladehum.ogg + soundFailToActivate: + path: /Audio/Machines/button.ogg + params: + variation: 0.250 + # Causes sound issues in combination with Rechargeable + #- type: ItemToggleActiveSound + # activeSound: + # path: /Audio/Weapons/ebladehum.ogg - type: ItemToggleSize activatedSize: Huge - type: ItemToggleDisarmMalus @@ -403,16 +408,17 @@ color: blue - type: Reflect enabled: false - reflectProb: 0.95 + reflectProb: 1 reflects: - Energy + damageOnReflect: true - type: Blocking passiveBlockModifier: coefficients: Blunt: 1.0 Slash: 0.9 Piercing: 0.85 - Heat: 0.6 + Heat: 0.5 activeBlockModifier: coefficients: Blunt: 1.2 @@ -425,27 +431,7 @@ - type: Appearance - type: Damageable damageContainer: Shield - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 180 - behaviors: - - !type:DoActsBehavior - acts: [ "Destruction" ] - - trigger: - !type:DamageTrigger - damage: 150 - behaviors: - - !type:DoActsBehavior - acts: [ "Destruction" ] - - !type:PlaySoundBehavior - sound: /Audio/Effects/metalbreak.ogg - - !type:SpawnEntitiesBehavior - spawn: - BrokenEnergyShield: - min: 1 - max: 1 + - type: Rechargeable - type: StaticPrice price: 350