Upstream core (#282)
* yes (cherry picked from commit a6b5e1c66dfe4241977bcde753af594392164eca) * Is real, navernoe (#944) * its real * fix shield * remove comments game preset * maximum predicted * fixes * АААААААААААААААААААААААААААА ПОМОГИТЕ Я ЕБНУЛСЯ ПОКА ФИКСИЛ ЭТУ ЗАЛУПУ * govnoedit * secret (cherry picked from commit 22c7b68048590b5098efbfff0d0f5205d3a64c48) * [Feature/Tweaks] Raznoe (#934) * make thruster great again * make hardsuit hos great again * new ficha for medical hud * fix * vrode da * GOOOVNO REMIX REVERB EXTRA * fix * правки --------- Co-authored-by: BIGZi0348 <svalker0348@gmail.com> (cherry picked from commit 141e61a0449873842f46d83eff9e9ce857147d60) * Automatic changelog update (cherry picked from commit d14fe5fb6c934ed522df0b5bc453e4c04707a6db) * [Feature] Executions (#932) * based * cleanup * cleanup + fixes * fix * fix * fix ftl * Update Resources/Locale/ru-RU/_white/executions/execution.ftl Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update execution.ftl * правки * vrode norm * da --------- Co-authored-by: BIGZi0348 <118811750+BIGZi0348@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: BIGZi0348 <svalker0348@gmail.com> (cherry picked from commit 83e164172f8e290acee7634f14ac51281be020ad) * Automatic changelog update (cherry picked from commit 71f907c563a30a1fc7ef5751a4d6f2c780a14f4c) * hotfix (#946) (cherry picked from commit f577caec41ab277ee8fc1c18fe64f7e26a6e50f5) --------- Co-authored-by: RavmorganButOnCocaine <valtos@nextmail.ru>
This commit is contained in:
@@ -42,8 +42,8 @@ public sealed class CultRuleSystem : GameRuleSystem<CultRuleComponent>
|
||||
[Dependency] private readonly ContainerSystem _container = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
[Dependency] private readonly GulagSystem _gulag = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -61,9 +61,6 @@ public sealed class CultRuleSystem : GameRuleSystem<CultRuleComponent>
|
||||
protected override void Added(EntityUid uid, CultRuleComponent rule, GameRuleComponent gameRule, GameRuleAddedEvent args)
|
||||
{
|
||||
base.Added(uid, rule, gameRule, args);
|
||||
|
||||
var potentialTargets = FindPotentialTargets();
|
||||
rule.CultTarget = _random.PickAndTake(potentialTargets).Mind;
|
||||
}
|
||||
|
||||
private void OnClone(Entity<CultistComponent> ent, ref CloningEvent args)
|
||||
@@ -266,6 +263,17 @@ public sealed class CultRuleSystem : GameRuleSystem<CultRuleComponent>
|
||||
|
||||
private void AfterEntitySelected(Entity<CultRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
|
||||
{
|
||||
if (ent.Comp.CultTarget == null)
|
||||
{
|
||||
var potentialTargets = FindPotentialTargets();
|
||||
if (potentialTargets.Count == 0)
|
||||
{
|
||||
ent.Comp.CultTarget = null;
|
||||
return;
|
||||
}
|
||||
ent.Comp.CultTarget = _random.PickAndTake(potentialTargets).Mind;
|
||||
}
|
||||
|
||||
MakeCultist(args.EntityUid, ent);
|
||||
}
|
||||
|
||||
@@ -335,12 +343,11 @@ public sealed class CultRuleSystem : GameRuleSystem<CultRuleComponent>
|
||||
|
||||
private List<MindContainerComponent> FindPotentialTargets()
|
||||
{
|
||||
var querry =
|
||||
EntityManager.EntityQueryEnumerator<MindContainerComponent, HumanoidAppearanceComponent, ActorComponent>();
|
||||
var query = EntityQueryEnumerator<MindContainerComponent, HumanoidAppearanceComponent, ActorComponent>();
|
||||
|
||||
var potentialTargets = new List<MindContainerComponent>();
|
||||
|
||||
while (querry.MoveNext(out var uid, out var mind, out _, out var actor))
|
||||
while (query.MoveNext(out var uid, out var mind, out _, out var actor))
|
||||
{
|
||||
var entity = mind.Mind;
|
||||
|
||||
@@ -350,7 +357,7 @@ public sealed class CultRuleSystem : GameRuleSystem<CultRuleComponent>
|
||||
if (_gulag.IsUserGulagged(actor.PlayerSession.UserId, out _))
|
||||
continue;
|
||||
|
||||
if (HasComp<CultistComponent>(entity))
|
||||
if (HasComp<CultistComponent>(uid))
|
||||
continue;
|
||||
|
||||
potentialTargets.Add(mind);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Server._White.Cult.Items.Components;
|
||||
using Content.Shared._White.Chaplain;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Throwing;
|
||||
using CultistComponent = Content.Shared._White.Cult.Components.CultistComponent;
|
||||
@@ -25,12 +26,16 @@ public sealed class ReturnItemOnThrowSystem : EntitySystem
|
||||
{
|
||||
var isCultist = HasComp<CultistComponent>(args.Target);
|
||||
var thrower = args.Component.Thrower;
|
||||
var isHumanoid = HasComp<HumanoidAppearanceComponent>(args.Target);
|
||||
if (!HasComp<CultistComponent>(thrower))
|
||||
return;
|
||||
|
||||
if (!HasComp<MobStateComponent>(args.Target))
|
||||
return;
|
||||
|
||||
if(!isHumanoid)
|
||||
return;
|
||||
|
||||
if (!isCultist && !_holyWeapon.IsHoldingHolyWeapon(args.Target))
|
||||
{
|
||||
_stun.TryParalyze(args.Target, TimeSpan.FromSeconds(component.StunTime), true);
|
||||
|
||||
@@ -1327,13 +1327,15 @@ public sealed partial class CultSystem : EntitySystem
|
||||
if (transform == null)
|
||||
return false;
|
||||
|
||||
if (!mindComponent.Mind.HasValue)
|
||||
if (mindComponent.Mind.HasValue == false)
|
||||
return false;
|
||||
|
||||
var shard = _entityManager.SpawnEntity("SoulShard", transform.Value);
|
||||
|
||||
if (shard.Valid == false)
|
||||
return false;
|
||||
|
||||
_mindSystem.TransferTo(mindComponent.Mind.Value, shard);
|
||||
_mindSystem.UnVisit(mindComponent.Mind.Value);
|
||||
|
||||
_bodySystem.GibBody(target);
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ public sealed class CultStructureCraftSystem : EntitySystem
|
||||
if (!HasComp<CultistComponent>(args.User))
|
||||
return;
|
||||
|
||||
_uiSystem.CloseUi(uid, component.UserInterfaceKey, args.User);
|
||||
if(_uiSystem.HasUi(args.User, component.UserInterfaceKey))
|
||||
_uiSystem.CloseUi(uid, component.UserInterfaceKey, args.User);
|
||||
|
||||
_uiSystem.OpenUi(uid, component.UserInterfaceKey, args.User);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared._White.Cult;
|
||||
using Content.Shared._White.Cult.UI;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Server._White.Cult.TimedProduction;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CultistFactoryComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField("cooldown")]
|
||||
public int Cooldown = 240;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public TimeSpan? NextTimeUse;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField("products", customTypeSerializer: typeof(PrototypeIdListSerializer<CultistFactoryProductionPrototype>))]
|
||||
public IReadOnlyCollection<string> Products = ArraySegment<string>.Empty;
|
||||
|
||||
public Enum UserInterfaceKey = CultistAltarUiKey.Key;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool Active = true;
|
||||
}
|
||||
@@ -4,9 +4,11 @@ using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared._White.Cult;
|
||||
using Content.Shared._White.Cult.Components;
|
||||
using Content.Shared._White.Cult.Structures;
|
||||
using Content.Shared._White.Cult.Systems;
|
||||
using Content.Shared._White.Cult.UI;
|
||||
using Content.Shared.UserInterface;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
@@ -37,11 +39,12 @@ public sealed class CultistFactorySystem : EntitySystem
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CultistFactoryComponent, InteractHandEvent>(OnInteract);
|
||||
SubscribeLocalEvent<CultistFactoryComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<CultistFactoryComponent, CultistFactoryItemSelectedMessage>(OnSelected);
|
||||
|
||||
SubscribeLocalEvent<CultistFactoryComponent, InteractUsingEvent>(TryToggleAnchor);
|
||||
SubscribeLocalEvent<CultistFactoryComponent, BeforeActivatableUIOpenEvent>((u, c, args) => UpdateUserInterfaceState(u, args, c));
|
||||
SubscribeLocalEvent<CultistFactoryComponent, ActivatableUIOpenAttemptEvent>((u, c, args) => OnActivatableUI(u, args, c));
|
||||
SubscribeLocalEvent<CultistFactoryComponent, CultAnchorDoAfterEvent>(OnAnchorDoAfter);
|
||||
SubscribeLocalEvent<CultistFactoryComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<CultistFactoryComponent, ConcealEvent>(OnConceal);
|
||||
@@ -70,28 +73,32 @@ public sealed class CultistFactorySystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, CultistFactoryComponent component, ComponentInit args)
|
||||
public void UpdateUserInterfaceState(EntityUid uid, BeforeActivatableUIOpenEvent args, CultistFactoryComponent? component = null)
|
||||
{
|
||||
UpdateAppearance(uid, component);
|
||||
}
|
||||
|
||||
private void OnInteract(EntityUid uid, CultistFactoryComponent component, InteractHandEvent args)
|
||||
{
|
||||
if (!HasComp<ActorComponent>(args.User))
|
||||
return;
|
||||
|
||||
if (!HasComp<CultistComponent>(args.User))
|
||||
return;
|
||||
|
||||
if (!CanCraft(uid, component, args.User))
|
||||
return;
|
||||
|
||||
var xform = Transform(uid);
|
||||
if (!xform.Anchored)
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
_ui.SetUiState(uid, CultistAltarUiKey.Key, new CultistFactoryBUIState(component.Products));
|
||||
_ui.OpenUi(uid, CultistAltarUiKey.Key, uid);
|
||||
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
private void OnActivatableUI(EntityUid uid, ActivatableUIOpenAttemptEvent args, CultistFactoryComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
var user = args.User;
|
||||
|
||||
if (!HasComp<CultistComponent>(user))
|
||||
args.Cancel();
|
||||
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, CultistFactoryComponent component, ComponentInit args)
|
||||
{
|
||||
UpdateAppearance(uid, component);
|
||||
}
|
||||
|
||||
private void OnSelected(EntityUid uid, CultistFactoryComponent component, CultistFactoryItemSelectedMessage args)
|
||||
|
||||
367
Content.Server/_White/Executions/ExecutionSystem.cs
Normal file
367
Content.Server/_White/Executions/ExecutionSystem.cs
Normal file
@@ -0,0 +1,367 @@
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Interaction;
|
||||
using Content.Server.Kitchen.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared._White.Executions;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Projectiles;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Weapons.Melee;
|
||||
using Content.Shared.Weapons.Ranged;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._White.Executions;
|
||||
|
||||
public sealed class ExecutionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
||||
[Dependency] private readonly InteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IComponentFactory _componentFactory = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||
[Dependency] private readonly SharedGunSystem _gunSystem = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
private const float MeleeExecutionTimeModifier = 5.0f;
|
||||
private const float GunExecutionTime = 6.0f;
|
||||
private const float DamageModifier = 10.0f;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SharpComponent, GetVerbsEvent<UtilityVerb>>(OnGetInteractionVerbsMelee);
|
||||
SubscribeLocalEvent<GunComponent, GetVerbsEvent<UtilityVerb>>(OnGetInteractionVerbsGun);
|
||||
|
||||
SubscribeLocalEvent<SharpComponent, ExecutionDoAfterEvent>(OnDoafterMelee);
|
||||
SubscribeLocalEvent<GunComponent, ExecutionDoAfterEvent>(OnDoafterGun);
|
||||
}
|
||||
|
||||
private void OnGetInteractionVerbsMelee(
|
||||
EntityUid uid,
|
||||
SharpComponent component,
|
||||
GetVerbsEvent<UtilityVerb> args)
|
||||
{
|
||||
if (args.Hands == null || args.Using == null || !args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
|
||||
var attacker = args.User;
|
||||
var weapon = args.Using.Value;
|
||||
var victim = args.Target;
|
||||
|
||||
if (!CanExecute(weapon, victim, attacker, true))
|
||||
return;
|
||||
|
||||
EnsureComp<ExecutionComponent>(weapon, out var comp);
|
||||
|
||||
if (IsDelayed(comp))
|
||||
return;
|
||||
|
||||
UtilityVerb verb = new()
|
||||
{
|
||||
Act = () =>
|
||||
{
|
||||
TryStartMeleeExecutionDoafter(weapon, victim, attacker);
|
||||
},
|
||||
Impact = LogImpact.High,
|
||||
Text = Loc.GetString("execution-verb-name"),
|
||||
Message = Loc.GetString("execution-verb-message"),
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
private void OnGetInteractionVerbsGun(
|
||||
EntityUid uid,
|
||||
GunComponent component,
|
||||
GetVerbsEvent<UtilityVerb> args)
|
||||
{
|
||||
if (args.Hands == null || args.Using == null || !args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
|
||||
var attacker = args.User;
|
||||
var weapon = args.Using!.Value;
|
||||
var victim = args.Target;
|
||||
|
||||
if (!CanExecute(weapon, victim, attacker, false))
|
||||
return;
|
||||
|
||||
EnsureComp<ExecutionComponent>(weapon, out var comp);
|
||||
|
||||
if (IsDelayed(comp))
|
||||
return;
|
||||
|
||||
UtilityVerb verb = new()
|
||||
{
|
||||
Act = () =>
|
||||
{
|
||||
TryStartGunExecutionDoafter(weapon, victim, attacker);
|
||||
},
|
||||
Impact = LogImpact.High,
|
||||
Text = Loc.GetString("execution-verb-name"),
|
||||
Message = Loc.GetString("execution-verb-message"),
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
private bool CanExecuteWithAny(EntityUid victim, EntityUid attacker)
|
||||
{
|
||||
if (!HasComp<DamageableComponent>(victim))
|
||||
return false;
|
||||
|
||||
if (!TryComp<MobStateComponent>(victim, out var mobState))
|
||||
return false;
|
||||
|
||||
if (_mobStateSystem.IsDead(victim, mobState))
|
||||
return false;
|
||||
|
||||
if (!_actionBlockerSystem.CanAttack(attacker, victim))
|
||||
return false;
|
||||
|
||||
return victim == attacker || !_actionBlockerSystem.CanInteract(victim, null);
|
||||
}
|
||||
|
||||
private bool CanExecute(EntityUid weapon, EntityUid victim, EntityUid user, bool isMelee)
|
||||
{
|
||||
if (!CanExecuteWithAny(victim, user))
|
||||
return false;
|
||||
|
||||
if (isMelee)
|
||||
{
|
||||
return (TryComp<MeleeWeaponComponent>(weapon, out var melee) || melee!.Damage.GetTotal() <= 0.0f);
|
||||
}
|
||||
|
||||
return (TryComp<GunComponent>(weapon, out var gun) || !_gunSystem.CanShoot(gun!));
|
||||
}
|
||||
|
||||
|
||||
private void TryStartMeleeExecutionDoafter(EntityUid weapon, EntityUid victim, EntityUid attacker)
|
||||
{
|
||||
if (!CanExecute(weapon, victim, attacker, true))
|
||||
return;
|
||||
|
||||
var executionTime = (1.0f / Comp<MeleeWeaponComponent>(weapon).AttackRate) * MeleeExecutionTimeModifier;
|
||||
|
||||
ShowExecutionPopup(
|
||||
attacker == victim ? "suicide-popup-melee-initial-external" : "execution-popup-melee-initial-external",
|
||||
PopupType.Medium,
|
||||
attacker,
|
||||
victim,
|
||||
weapon);
|
||||
|
||||
var doAfter =
|
||||
new DoAfterArgs(EntityManager, attacker, executionTime, new ExecutionDoAfterEvent(), weapon, target: victim, used: weapon)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnHandChange = true,
|
||||
BreakOnDamage = true,
|
||||
NeedHand = true
|
||||
};
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(doAfter);
|
||||
|
||||
EnsureComp<ExecutionComponent>(weapon, out var comp);
|
||||
|
||||
comp.NextUse = _gameTiming.CurTime + comp.NextAttempt;
|
||||
}
|
||||
|
||||
private void TryStartGunExecutionDoafter(EntityUid weapon, EntityUid victim, EntityUid attacker)
|
||||
{
|
||||
if (!CanExecute(weapon, victim, attacker, false))
|
||||
return;
|
||||
|
||||
ShowExecutionPopup(
|
||||
attacker == victim ? "suicide-popup-gun-initial-external" : "execution-popup-gun-initial-external",
|
||||
PopupType.Medium,
|
||||
attacker,
|
||||
victim,
|
||||
weapon);
|
||||
|
||||
var doAfter =
|
||||
new DoAfterArgs(EntityManager, attacker, GunExecutionTime, new ExecutionDoAfterEvent(), weapon, target: victim, used: weapon)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnHandChange = true,
|
||||
BreakOnDamage = true,
|
||||
NeedHand = true
|
||||
};
|
||||
|
||||
_doAfterSystem.TryStartDoAfter(doAfter);
|
||||
|
||||
EnsureComp<ExecutionComponent>(weapon, out var comp);
|
||||
|
||||
comp.NextUse = _gameTiming.CurTime + comp.NextAttempt;
|
||||
}
|
||||
|
||||
private void OnDoafterMelee(EntityUid uid, SharpComponent component, DoAfterEvent args)
|
||||
{
|
||||
if (args.Handled || args.Cancelled || args.Used == null || args.Target == null)
|
||||
return;
|
||||
|
||||
var attacker = args.User;
|
||||
var victim = args.Target.Value;
|
||||
var weapon = args.Used.Value;
|
||||
|
||||
if (!CanExecute(weapon, victim, attacker, true))
|
||||
return;
|
||||
|
||||
if (!TryComp<MeleeWeaponComponent>(weapon, out var melee) && melee!.Damage.GetTotal() > 0.0f)
|
||||
return;
|
||||
|
||||
_damageableSystem.TryChangeDamage(victim, melee.Damage * DamageModifier, true);
|
||||
_audioSystem.PlayEntity(melee.HitSound, Filter.Pvs(weapon), weapon, true, AudioParams.Default);
|
||||
|
||||
ShowExecutionPopup(
|
||||
attacker == victim ? "suicide-popup-melee-complete-external" : "execution-popup-melee-complete-external",
|
||||
PopupType.MediumCaution,
|
||||
attacker,
|
||||
victim,
|
||||
weapon);
|
||||
}
|
||||
|
||||
private void OnDoafterGun(EntityUid uid, GunComponent component, DoAfterEvent args)
|
||||
{
|
||||
if (args.Handled || args.Cancelled || args.Used == null || args.Target == null)
|
||||
return;
|
||||
|
||||
var attacker = args.User;
|
||||
var weapon = args.Used.Value;
|
||||
var victim = args.Target.Value;
|
||||
|
||||
if (!CanExecute(weapon, victim, attacker, false))
|
||||
return;
|
||||
|
||||
var prevention = new ShotAttemptedEvent
|
||||
{
|
||||
User = attacker,
|
||||
Used = weapon!
|
||||
};
|
||||
|
||||
RaiseLocalEvent(weapon, ref prevention);
|
||||
if (prevention.Cancelled)
|
||||
return;
|
||||
|
||||
RaiseLocalEvent(attacker, ref prevention);
|
||||
if (prevention.Cancelled)
|
||||
return;
|
||||
|
||||
var attemptEv = new AttemptShootEvent(attacker, null);
|
||||
RaiseLocalEvent(weapon, ref attemptEv);
|
||||
|
||||
if (attemptEv is { Cancelled: true, Message: not null })
|
||||
{
|
||||
_popupSystem.PopupClient(attemptEv.Message, weapon, attacker);
|
||||
return;
|
||||
}
|
||||
|
||||
var fromCoordinates = Transform(attacker).Coordinates;
|
||||
var ev = new TakeAmmoEvent(1, new List<(EntityUid? Entity, IShootable Shootable)>(), fromCoordinates, attacker);
|
||||
RaiseLocalEvent(weapon, ev);
|
||||
|
||||
if (ev.Ammo.Count <= 0)
|
||||
{
|
||||
_audioSystem.PlayEntity(component.SoundEmpty, Filter.Pvs(weapon), weapon, true, AudioParams.Default);
|
||||
ShowExecutionPopup("execution-popup-gun-empty", PopupType.Medium, attacker, victim, weapon);
|
||||
return;
|
||||
}
|
||||
|
||||
var damage = new DamageSpecifier();
|
||||
|
||||
var ammoUid = ev.Ammo[0].Entity;
|
||||
switch (ev.Ammo[0].Shootable)
|
||||
{
|
||||
case CartridgeAmmoComponent cartridge:
|
||||
var prototype = _prototypeManager.Index<EntityPrototype>(cartridge.Prototype);
|
||||
prototype.TryGetComponent<ProjectileComponent>(out var projectileA, _componentFactory);
|
||||
if (projectileA != null)
|
||||
{
|
||||
damage = projectileA.Damage * cartridge.Count;
|
||||
}
|
||||
|
||||
cartridge.Spent = true;
|
||||
_appearanceSystem.SetData(ammoUid!.Value, AmmoVisuals.Spent, true);
|
||||
Dirty(ammoUid.Value, cartridge);
|
||||
|
||||
break;
|
||||
|
||||
case AmmoComponent:
|
||||
TryComp<ProjectileComponent>(ammoUid, out var projectileB);
|
||||
if (projectileB != null)
|
||||
{
|
||||
damage = projectileB.Damage;
|
||||
}
|
||||
Del(ammoUid);
|
||||
break;
|
||||
|
||||
case HitscanPrototype hitscan:
|
||||
damage = hitscan.Damage!;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (TryComp<ClumsyComponent>(attacker, out var clumsy) && !component.ClumsyProof)
|
||||
{
|
||||
if (_interactionSystem.TryRollClumsy(attacker, 0.3F, clumsy))
|
||||
{
|
||||
ShowExecutionPopup("execution-popup-gun-clumsy-external", PopupType.MediumCaution, attacker, victim, weapon);
|
||||
|
||||
_damageableSystem.TryChangeDamage(attacker, damage, origin: attacker);
|
||||
_audioSystem.PlayEntity(component.SoundGunshot, Filter.Pvs(weapon), weapon, true, AudioParams.Default);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_damageableSystem.TryChangeDamage(victim, damage * DamageModifier, true);
|
||||
_audioSystem.PlayEntity(component.SoundGunshot, Filter.Pvs(weapon), weapon, false, AudioParams.Default);
|
||||
|
||||
ShowExecutionPopup(
|
||||
attacker != victim ? "execution-popup-gun-complete-external" : "suicide-popup-gun-complete-external",
|
||||
PopupType.LargeCaution,
|
||||
attacker,
|
||||
victim,
|
||||
weapon);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void ShowExecutionPopup(string locString,
|
||||
PopupType type,
|
||||
EntityUid attacker,
|
||||
EntityUid victim,
|
||||
EntityUid weapon)
|
||||
{
|
||||
var message = Loc.GetString(locString,
|
||||
("attacker", attacker),
|
||||
("victim", victim),
|
||||
("weapon", weapon));
|
||||
|
||||
_popupSystem.PopupEntity(message, attacker, type);
|
||||
}
|
||||
|
||||
private bool IsDelayed(ExecutionComponent comp)
|
||||
{
|
||||
return comp.NextUse > _gameTiming.CurTime;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user