Files
OldThink/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs

386 lines
16 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
2021-11-29 02:34:44 +13:00
using Content.Server.Administration.Logs;
using Content.Server.Body.Components;
2021-11-30 16:47:21 -07:00
using Content.Server.Body.Systems;
2021-06-09 22:19:39 +02:00
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.EntitySystems;
2021-06-09 22:19:39 +02:00
using Content.Server.Cooldown;
using Content.Server.Weapon.Melee.Components;
ECS damageable (#4529) * ECS and damage Data * Comments and newlines * Added Comments * Make TryChangeDamageEvent immutable * Remove SetAllDamage event Use public SetAllDamage function instead * Undo destructible mistakes That was some shit code. * Rename DamageData to DamageSpecifier And misc small edits misc * Cache trigger prototypes. * Renaming destructible classes & functions * Revert "Cache trigger prototypes." This reverts commit 86bae15ba6616884dba75f552dfdfbe2d1fb6586. * Replace prototypes with prototype IDs. * Split damage.yml into individual files * move get/handle component state to system * Update HealthChange doc * Make godmode call Dirty() on damageable component * Add Initialize() to fix damage test * Make non-static * uncache resistance set prototype and trim DamageableComponentState * Remove unnecessary Dirty() calls during initialization * RemoveTryChangeDamageEvent * revert Dirty() * Fix MobState relying on DamageableComponent.Dirty() * Fix DisposalUnit Tests. These were previously failing, but because the async was not await-ed, this never raised the exception. After I fixed MobState component, this exception stopped happening and instead the assertions started being tested & failing * Disposal test 2: electric boogaloo * Fix typos/mistakes also add comments and fix spacing. * Use Uids instead of IEntity * fix merge * Comments, a merge issue, and making some damage ignore resistances * Extend DamageSpecifier and use it for DamageableComponent * fix master merge * Fix Disposal unit test. Again. Snapgrids were removed in master * Execute Exectute
2021-09-15 03:07:37 +10:00
using Content.Shared.Damage;
using Content.Shared.Sound;
using Content.Shared.Audio;
2021-11-28 14:56:53 +01:00
using Content.Shared.Database;
2021-06-09 22:19:39 +02:00
using Content.Shared.Hands;
using Content.Shared.Interaction;
using Content.Shared.Physics;
2021-06-09 22:19:39 +02:00
using Content.Shared.Weapons.Melee;
using Robust.Shared.Audio;
2021-09-20 08:40:22 +02:00
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Player;
using Robust.Shared.Timing;
2021-06-09 22:19:39 +02:00
namespace Content.Server.Weapon.Melee
{
public sealed class MeleeWeaponSystem : EntitySystem
{
[Dependency] private IGameTiming _gameTiming = default!;
ECS damageable (#4529) * ECS and damage Data * Comments and newlines * Added Comments * Make TryChangeDamageEvent immutable * Remove SetAllDamage event Use public SetAllDamage function instead * Undo destructible mistakes That was some shit code. * Rename DamageData to DamageSpecifier And misc small edits misc * Cache trigger prototypes. * Renaming destructible classes & functions * Revert "Cache trigger prototypes." This reverts commit 86bae15ba6616884dba75f552dfdfbe2d1fb6586. * Replace prototypes with prototype IDs. * Split damage.yml into individual files * move get/handle component state to system * Update HealthChange doc * Make godmode call Dirty() on damageable component * Add Initialize() to fix damage test * Make non-static * uncache resistance set prototype and trim DamageableComponentState * Remove unnecessary Dirty() calls during initialization * RemoveTryChangeDamageEvent * revert Dirty() * Fix MobState relying on DamageableComponent.Dirty() * Fix DisposalUnit Tests. These were previously failing, but because the async was not await-ed, this never raised the exception. After I fixed MobState component, this exception stopped happening and instead the assertions started being tested & failing * Disposal test 2: electric boogaloo * Fix typos/mistakes also add comments and fix spacing. * Use Uids instead of IEntity * fix merge * Comments, a merge issue, and making some damage ignore resistances * Extend DamageSpecifier and use it for DamageableComponent * fix master merge * Fix Disposal unit test. Again. Snapgrids were removed in master * Execute Exectute
2021-09-15 03:07:37 +10:00
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private SolutionContainerSystem _solutionsSystem = default!;
2021-11-29 02:34:44 +13:00
[Dependency] private readonly AdminLogSystem _logSystem = default!;
2021-11-30 16:47:21 -07:00
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
Damageable Refactor 3: Revenge of the Instamerge (#4524) * Add DamageType And DamageGroup Prototypes * Remove DamageTypePrototype Field "name" as its redundant * Change I/DamageableComponent to use prototypes * Update DamageContainer, ReisistanceSet and DamageChangeData * Change Barotrauma Component to use DamageType from DamageSystem * Update AsteroidRockComponent * update some more components * update some more components * Fix m o r e c o m p o n e n t s and their damageType * all thats left is bug/missing node hunting then verification. * push changes * update submodule * Merge fixes * push DGP for example * update damagecomponent across shared and server * fix a few bugs * Fix Merge issues * Refactor damageablecomponent update (#4406) * Fixing merge. I messed up part of the merge. this should fix it? * Barotrauma now uses prototypeManager As System.Runtime.CompilerServices also has a [Dependency], I think I had to use the full path [Robust.Shared.IoC.Dependency] * FlammableComponent now uses prototypeManager * SuicideCommands now use prototypeManager * Changed many files to use prototypeManager to resolve damaege prototypes Yeah.... prototype references would be very nice. maybe this was all a waste of time. * Grouping prototypeManager.Index with datafield definitions This will make it easier to eventually add prototype references * removed unused variable * Moved lines around. Lines now consistent with other TODO PROTOTYPE blocks * Grouping more prototypeManager.Index with datafield definitions * Removed unnecessary code * Added more prototypeManager indexing These ones weren't pointed out by DrSmug. But I think this is all of them? That or my regex is shit. * Remove redundant _damage field * Remove redundant _currentTemperature * Moved variables down * Added prototypeManager indexing to TemperatureComponent * WeaponComponent/System now use ProtptypeManager And as far as I can tell damageType is required, and therefore should never have been null anyway? * Make ranged weapon clumsy fire effects datafields And yes, the order in which the clumsy effects occur is very important. * Made damage on vital body part loss a datafield * Renamed several damageGroup variables to group * Capitalised DamageListToDamageGroup * Make radiation and explosion damage types datafields * Renamed _supportedDamageGroupIDs and _supportedDamageTypeIDs * Fixed mistakes Frogot to remove prototypeManager index DamageTypeTrigger, and wrong variable visibility in TemperatureComponent * Added necessary code Is something tragically wrong? * MeleeWeapon damageType is not actually required * Fixing someone else's mistakes A search comes up with nothing in the yaml files, and its not a required field. So no one uses it? Hopefully? * Changed and renamed damageTypeToDamageGroup Previously would incorrectly return the total container damage for each group, not the total in the group * renaming varitables * Renamed variable DamageClasses * Added dictionary converting functions * Added ID-keyed dictionaries * Making MedicalScanner use ID dictionaries, instead of prototype dictionaries Oh oh no. I've been able to avoid UI & networking up until now. I have no Idea what I am doing. * Fix Medical Scanner * Summary (required) The joke here is that this fixes the empty summary. * Removed DamageableComponent.GetDamageGroup/Type * Renamed "damage classes" to groups. * Update ChangeDamage description * Replaced Heal() with SettAllDamage() Heal() was just a confusing name, * More Class -> Group renaming * Replace Class with Group in yaml files DamageClassTrigger does not appear in any yaml? only in testing? DamageTypeTrigger appears only in human.yaml? HealthChangeMetabolism is Mostly in medicine.yml and one in soad.yaml Why the hell is Cola metabolizable by plants? Who is pouring cola on their plants!?!? * Fix _prototypeManager being null errors. * Changing comments Where are the prototype references * MetabolismComponent doesn't give free heals anymore. * Changes HungerComponent healing. Previously I think it would actually damage you. Only did this as I though it was causing the fast healing. Turns out that was just BREATHING. * Generalised a function in DamageableComponent and moved it to DamageGroupPrototype previously DamageTypesDictToDamageGroupDict was private to DamageableComponent, but was also quite general (nearly a static function). As this sort of function may be needed by other components using DamageGroupPrototypes in the future, I moved it there as a static function instead. * modified DamageableComponent.ChangeDamage() ignoreResistances was renamed to ignoreDamageResistances to make it clearer that it had no effect on healing. Now uses default argument for ignoreDamageResistances, so when healing you are not forced to specify an argument that does nothing. Also made some general changes to ignoreResistances() * Changed class->group and added missing damage type functionality to DamageContainerPrototypes * Added Comments to damage.yml * Misc Changes to DamageableComponent * Differentiated between group support and group applicability So far, every damage type is a member of one, and only one, damage group. So this change has no real effect so far. * Added proposed alternative to ChangeDamage() * fixed error in DamageGroupPrototype * Changes to DamageableComponent Lots of changes to comments. Some variables renamed in IDamageableComponent and DamageableComponent (also required renaming in other files) Some minor logic changes, mostly for incorrect descirptions of boolean return values. Also further differentiating between ApplicableGroups and SupportedGroups... if that will ever even matter * Generalised MedicalScannerComponent If needed, can print miscellaneous damage types now * Fixed HealthChangeMetabolism bug * Changing Comments around * More questions * Made Barotrauma default to blunt * Fix RejuvenateTest.cs * Comments * Coments and variable names * fix some master-merge issues * Removed redundant fields * Misc changes for readbility of PR diff * Consistent naming * Fixed atmos damage bug * Removed Ranting * Fixed Hunger after I broke it * Fixing Bugs * Removed stupid question * Removed more stupid questions * Fix potential null errors. * Made boolean return values consistent Also renamed several functions, to make it clear they return a bool. Docs were also updated. * Removed IoCManager.InjectDependencies() * Removed unnecessary 'suffocation' prefix * Fixed Spelling Also removed accidentally left in logger call * Fixed Medical Scanner * Apply suggestions from code review Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> * Changing comments and whitespaces * Made damage thresholds trigger datafields required * So many typos * Changes to DamageableComponents Changed documentation in IDamageableComponent Made testing code more readable. Relabelled groups as 'Applicable' either 'Fully Supported' * Removed function and degeneralised * Update DamageableComponent.cs Removed unused parameters Fixed Networking * Added IoCManager.Resolve * Now using alternative TryChangeDamage() * Removed function from DamageGroupPrototype * Removing comments * Remove bad if statement? * Fix damageChanged ordering * Fix hurt server command * Changed //TODO PROTOTYPE blocks Now use PrototypeManager differently. Wherever possible, only retrieve the prototype once. Also added default damage types to some more datafields * Update Content.Shared/Damage/Container/DamageContainerPrototype.cs Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> * renamed _accumulatedHealth -> _accumulatedDamage and added TODOs * Another class-> group * Fix bug in generalisation of damage container prototypes * Addes Tests to make sure I dont keep adding bugs to my own code. * Changed Return values when setting * Removed unused class * Added more tests, split tests into three files * Made damage types public and VV read-write-able * Minor changes to DamageableComponent Replaced internal use of GetDamagePerType with _damageDict and removed some unnecessary fields * Fix Suicide, by adding IoC Resolve() * Fix DamageGroupTrigger bug * Fix typos in tests * Change comments./docstrings & spacing * Merge tests, use test prototypes Co-authored-by: Leon Friedrich <60421075+leonsfriedrich@users.noreply.github.com> Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> * Fix merge issues Co-authored-by: Silver <Silvertorch5@gmail.com> Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com> Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Co-authored-by: Leon Friedrich <60421075+leonsfriedrich@users.noreply.github.com>
2021-08-25 03:06:27 +10:00
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<MeleeWeaponComponent, HandSelectedEvent>(OnHandSelected);
SubscribeLocalEvent<MeleeWeaponComponent, ClickAttackEvent>(OnClickAttack);
SubscribeLocalEvent<MeleeWeaponComponent, WideAttackEvent>(OnWideAttack);
SubscribeLocalEvent<MeleeWeaponComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<MeleeChemicalInjectorComponent, MeleeHitEvent>(OnChemicalInjectorHit);
}
private void OnHandSelected(EntityUid uid, MeleeWeaponComponent comp, HandSelectedEvent args)
{
var curTime = _gameTiming.CurTime;
var cool = TimeSpan.FromSeconds(comp.CooldownTime * 0.5f);
if (curTime < comp.CooldownEnd)
{
if (comp.CooldownEnd - curTime < cool)
{
comp.LastAttackTime = curTime;
comp.CooldownEnd += cool;
}
else
return;
}
else
{
comp.LastAttackTime = curTime;
comp.CooldownEnd = curTime + cool;
}
RaiseLocalEvent(uid, new RefreshItemCooldownEvent(comp.LastAttackTime, comp.CooldownEnd), false);
}
2021-12-05 18:09:01 +01:00
private void OnClickAttack(EntityUid owner, MeleeWeaponComponent comp, ClickAttackEvent args)
{
2021-06-05 18:05:57 +02:00
args.Handled = true;
var curTime = _gameTiming.CurTime;
if (curTime < comp.CooldownEnd || args.Target == null)
return;
var location = EntityManager.GetComponent<TransformComponent>(args.User).Coordinates;
var diff = args.ClickLocation.ToMapPos(EntityManager) - location.ToMapPos(EntityManager);
var angle = Angle.FromWorldVec(diff);
2021-12-05 18:09:01 +01:00
if (args.Target is {Valid: true} target)
{
// Raise event before doing damage so we can cancel damage if the event is handled
2021-12-05 18:09:01 +01:00
var hitEvent = new MeleeHitEvent(new List<EntityUid>() { target }, args.User);
RaiseLocalEvent(owner, hitEvent, false);
if (!hitEvent.Handled)
{
var targets = new[] { target };
SendAnimation(comp.ClickArc, angle, args.User, owner, targets, comp.ClickAttackEffect, false);
2021-12-03 15:53:09 +01:00
RaiseLocalEvent(target, new AttackedEvent(args.Used, args.User, args.ClickLocation));
var modifiedDamage = DamageSpecifier.ApplyModifierSets(comp.Damage + hitEvent.BonusDamage, hitEvent.ModifiersList);
var damageResult = _damageableSystem.TryChangeDamage(target, modifiedDamage);
2021-11-29 02:34:44 +13:00
if (damageResult != null)
2021-11-29 02:34:44 +13:00
{
if (args.Used == args.User)
_logSystem.Add(LogType.MeleeHit,
$"{ToPrettyString(args.User):user} melee attacked {ToPrettyString(args.Target.Value):target} using their hands and dealt {damageResult.Total:damage} damage");
2021-11-29 02:34:44 +13:00
else
_logSystem.Add(LogType.MeleeHit,
$"{ToPrettyString(args.User):user} melee attacked {ToPrettyString(args.Target.Value):target} using {ToPrettyString(args.Used):used} and dealt {damageResult.Total:damage} damage");
2021-11-29 02:34:44 +13:00
}
if (hitEvent.HitSoundOverride != null)
{
SoundSystem.Play(Filter.Pvs(owner), hitEvent.HitSoundOverride.GetSound(), target, AudioHelpers.WithVariation(0.25f));
}
else
{
SoundSystem.Play(Filter.Pvs(owner), comp.HitSound.GetSound(), target);
}
}
}
else
{
SoundSystem.Play(Filter.Pvs(owner), comp.MissSound.GetSound(), args.User);
return;
}
comp.LastAttackTime = curTime;
comp.CooldownEnd = comp.LastAttackTime + TimeSpan.FromSeconds(comp.CooldownTime);
2021-12-05 18:09:01 +01:00
RaiseLocalEvent(owner, new RefreshItemCooldownEvent(comp.LastAttackTime, comp.CooldownEnd), false);
}
2021-12-05 18:09:01 +01:00
private void OnWideAttack(EntityUid owner, MeleeWeaponComponent comp, WideAttackEvent args)
{
2021-06-05 18:05:57 +02:00
args.Handled = true;
var curTime = _gameTiming.CurTime;
if (curTime < comp.CooldownEnd)
{
return;
}
var location = EntityManager.GetComponent<TransformComponent>(args.User).Coordinates;
var diff = args.ClickLocation.ToMapPos(EntityManager) - location.ToMapPos(EntityManager);
var angle = Angle.FromWorldVec(diff);
// This should really be improved. GetEntitiesInArc uses pos instead of bounding boxes.
var entities = ArcRayCast(EntityManager.GetComponent<TransformComponent>(args.User).WorldPosition, angle, comp.ArcWidth, comp.Range, EntityManager.GetComponent<TransformComponent>(owner).MapID, args.User);
2021-12-05 18:09:01 +01:00
var hitEntities = new List<EntityUid>();
foreach (var entity in entities)
{
2021-09-20 08:40:22 +02:00
if (entity.IsInContainer() || entity == args.User)
continue;
2021-12-03 15:53:09 +01:00
if (EntityManager.HasComponent<DamageableComponent>(entity))
{
hitEntities.Add(entity);
}
}
// Raise event before doing damage so we can cancel damage if handled
var hitEvent = new MeleeHitEvent(hitEntities, args.User);
2021-12-05 18:09:01 +01:00
RaiseLocalEvent(owner, hitEvent, false);
SendAnimation(comp.Arc, angle, args.User, owner, hitEntities);
if (!hitEvent.Handled)
{
if (entities.Count != 0)
{
2022-01-25 11:22:25 +11:00
if (hitEvent.HitSoundOverride != null)
{
SoundSystem.Play(Filter.Pvs(owner), hitEvent.HitSoundOverride.GetSound(), Transform(entities.First()).Coordinates);
}
else
{
SoundSystem.Play(Filter.Pvs(owner), comp.HitSound.GetSound(), Transform(entities.First()).Coordinates);
}
}
else
{
2022-01-25 11:22:25 +11:00
SoundSystem.Play(Filter.Pvs(owner), comp.MissSound.GetSound(), Transform(args.User).Coordinates);
}
var modifiedDamage = DamageSpecifier.ApplyModifierSets(comp.Damage + hitEvent.BonusDamage, hitEvent.ModifiersList);
foreach (var entity in hitEntities)
{
2021-12-03 15:53:09 +01:00
RaiseLocalEvent(entity, new AttackedEvent(args.Used, args.User, args.ClickLocation));
var damageResult = _damageableSystem.TryChangeDamage(entity, modifiedDamage);
2021-11-29 02:34:44 +13:00
if (damageResult != null)
2021-11-29 02:34:44 +13:00
{
if (args.Used == args.User)
_logSystem.Add(LogType.MeleeHit,
$"{ToPrettyString(args.User):user} melee attacked {ToPrettyString(entity):target} using their hands and dealt {damageResult.Total:damage} damage");
2021-11-29 02:34:44 +13:00
else
_logSystem.Add(LogType.MeleeHit,
$"{ToPrettyString(args.User):user} melee attacked {ToPrettyString(entity):target} using {ToPrettyString(args.Used):used} and dealt {damageResult.Total:damage} damage");
2021-11-29 02:34:44 +13:00
}
}
}
comp.LastAttackTime = curTime;
comp.CooldownEnd = comp.LastAttackTime + TimeSpan.FromSeconds(comp.ArcCooldownTime);
2021-12-05 18:09:01 +01:00
RaiseLocalEvent(owner, new RefreshItemCooldownEvent(comp.LastAttackTime, comp.CooldownEnd), false);
}
/// <summary>
/// Used for melee weapons that want some behavior on AfterInteract,
/// but also want the cooldown (stun batons, flashes)
/// </summary>
2021-12-05 18:09:01 +01:00
private void OnAfterInteract(EntityUid owner, MeleeWeaponComponent comp, AfterInteractEvent args)
{
if (args.Handled || !args.CanReach)
return;
var curTime = _gameTiming.CurTime;
if (curTime < comp.CooldownEnd)
{
return;
}
2021-12-05 21:02:04 +01:00
if (!args.Target.HasValue)
return;
var location = EntityManager.GetComponent<TransformComponent>(args.User).Coordinates;
var diff = args.ClickLocation.ToMapPos(EntityManager) - location.ToMapPos(EntityManager);
var angle = Angle.FromWorldVec(diff);
2021-12-05 21:02:04 +01:00
var hitEvent = new MeleeInteractEvent(args.Target.Value, args.User);
2021-12-05 18:09:01 +01:00
RaiseLocalEvent(owner, hitEvent, false);
if (!hitEvent.CanInteract) return;
2021-12-05 21:02:04 +01:00
SendAnimation(comp.ClickArc, angle, args.User, owner, new List<EntityUid>() { args.Target.Value }, comp.ClickAttackEffect, false);
comp.LastAttackTime = curTime;
comp.CooldownEnd = comp.LastAttackTime + TimeSpan.FromSeconds(comp.CooldownTime);
2021-12-05 18:09:01 +01:00
RaiseLocalEvent(owner, new RefreshItemCooldownEvent(comp.LastAttackTime, comp.CooldownEnd), false);
}
2021-12-05 18:09:01 +01:00
private HashSet<EntityUid> ArcRayCast(Vector2 position, Angle angle, float arcWidth, float range, MapId mapId, EntityUid ignore)
{
var widthRad = Angle.FromDegrees(arcWidth);
var increments = 1 + 35 * (int) Math.Ceiling(widthRad / (2 * Math.PI));
var increment = widthRad / increments;
var baseAngle = angle - widthRad / 2;
2021-12-05 18:09:01 +01:00
var resSet = new HashSet<EntityUid>();
for (var i = 0; i < increments; i++)
{
var castAngle = new Angle(baseAngle + increment * i);
var res = Get<SharedPhysicsSystem>().IntersectRay(mapId,
new CollisionRay(position, castAngle.ToWorldVec(),
(int) (CollisionGroup.Impassable | CollisionGroup.MobImpassable)), range, ignore).ToList();
if (res.Count != 0)
{
resSet.Add(res[0].HitEntity);
}
}
return resSet;
}
2021-12-05 18:09:01 +01:00
private void OnChemicalInjectorHit(EntityUid owner, MeleeChemicalInjectorComponent comp, MeleeHitEvent args)
{
2021-12-03 15:53:09 +01:00
if (!_solutionsSystem.TryGetInjectableSolution(owner, out var solutionContainer))
return;
var hitBloodstreams = new List<BloodstreamComponent>();
foreach (var entity in args.HitEntities)
{
2021-12-09 12:29:27 +01:00
if (Deleted(entity))
continue;
if (EntityManager.TryGetComponent<BloodstreamComponent?>(entity, out var bloodstream))
hitBloodstreams.Add(bloodstream);
}
if (hitBloodstreams.Count < 1)
return;
var removedSolution = solutionContainer.SplitSolution(comp.TransferAmount * hitBloodstreams.Count);
var removedVol = removedSolution.TotalVolume;
var solutionToInject = removedSolution.SplitSolution(removedVol * comp.TransferEfficiency);
var volPerBloodstream = solutionToInject.TotalVolume * (1 / hitBloodstreams.Count);
foreach (var bloodstream in hitBloodstreams)
{
var individualInjection = solutionToInject.SplitSolution(volPerBloodstream);
2022-02-17 15:00:41 -07:00
_bloodstreamSystem.TryAddToChemicals((bloodstream).Owner, individualInjection, bloodstream);
}
}
2021-12-05 18:09:01 +01:00
public void SendAnimation(string arc, Angle angle, EntityUid attacker, EntityUid source, IEnumerable<EntityUid> hits, bool textureEffect = false, bool arcFollowAttacker = true)
{
2021-12-03 15:53:09 +01:00
RaiseNetworkEvent(new MeleeWeaponSystemMessages.PlayMeleeWeaponAnimationMessage(arc, angle, attacker, source,
2021-12-05 18:09:01 +01:00
hits.Select(e => e).ToList(), textureEffect, arcFollowAttacker), Filter.Pvs(source, 1f));
}
2021-12-05 18:09:01 +01:00
public void SendLunge(Angle angle, EntityUid source)
{
2021-12-03 15:53:09 +01:00
RaiseNetworkEvent(new MeleeWeaponSystemMessages.PlayLungeAnimationMessage(angle, source), Filter.Pvs(source, 1f));
}
}
/// <summary>
/// Raised directed on the melee weapon entity used to attack something in combat mode,
/// whether through a click attack or wide attack.
/// </summary>
public sealed class MeleeHitEvent : HandledEntityEventArgs
{
/// <summary>
/// Modifier sets to apply to the hit event when it's all said and done.
/// This should be modified by adding a new entry to the list.
/// </summary>
public List<DamageModifierSet> ModifiersList = new();
/// <summary>
/// Damage to add to the default melee weapon damage. Applied before modifiers.
/// </summary>
/// <remarks>
/// This might be required as damage modifier sets cannot add a new damage type to a DamageSpecifier.
/// </remarks>
public DamageSpecifier BonusDamage = new();
/// <summary>
/// A list containing every hit entity. Can be zero.
/// </summary>
2021-12-05 18:09:01 +01:00
public IEnumerable<EntityUid> HitEntities { get; }
/// <summary>
/// Used to define a new hit sound in case you want to override the default GenericHit.
/// Also gets a pitch modifier added to it.
/// </summary>
public SoundSpecifier? HitSoundOverride {get; set;}
/// <summary>
/// The user who attacked with the melee weapon.
/// </summary>
2021-12-05 18:09:01 +01:00
public EntityUid User { get; }
2021-12-05 18:09:01 +01:00
public MeleeHitEvent(List<EntityUid> hitEntities, EntityUid user)
{
HitEntities = hitEntities;
User = user;
}
}
/// <summary>
/// Raised directed on the melee weapon entity used to attack something in combat mode,
/// whether through a click attack or wide attack.
/// </summary>
public sealed class MeleeInteractEvent : EntityEventArgs
{
/// <summary>
/// The entity interacted with.
/// </summary>
2021-12-05 18:09:01 +01:00
public EntityUid Entity { get; }
/// <summary>
/// The user who interacted using the melee weapon.
/// </summary>
2021-12-05 18:09:01 +01:00
public EntityUid User { get; }
/// <summary>
/// Modified by the event handler to specify whether they could successfully interact with the entity.
/// Used to know whether to send the hit animation or not.
/// </summary>
public bool CanInteract { get; set; } = false;
2021-12-05 18:09:01 +01:00
public MeleeInteractEvent(EntityUid entity, EntityUid user)
{
Entity = entity;
User = user;
}
}
}