119 lines
2.6 KiB
C#
119 lines
2.6 KiB
C#
using System.Threading.Tasks;
|
|
using Sandbox.UI;
|
|
using Sasalka;
|
|
|
|
namespace Sandbox.Weapons;
|
|
|
|
public sealed class Weapon : AmmoUseableBase
|
|
{
|
|
[Property] public SkinnedModelRenderer GunRenderer { get; private set; }
|
|
[Property] public GameObject MuzzleLight { get; private set; }
|
|
[Property] public GameObject particlePrefab { get; set; }
|
|
[Property] public GameObject bloodParticle { get; set; }
|
|
[Property] public WeaponItemDefinition WeaponDefinition { get; set; }
|
|
|
|
private SoundPointComponent _sound;
|
|
private Rigidbody _rigidbody;
|
|
|
|
protected override void OnStart()
|
|
{
|
|
base.OnStart();
|
|
_sound = GameObject.GetComponent<SoundPointComponent>(true);
|
|
}
|
|
|
|
public override void OnEquipped()
|
|
{
|
|
_rigidbody = GameObject.Components.Get<Rigidbody>();
|
|
_rigidbody.Enabled = false;
|
|
GameObject.Components.Get<PickupItem>().Enabled = false;
|
|
}
|
|
|
|
protected override WeaponItemDefinition GetWeaponDefinition()
|
|
{
|
|
return WeaponDefinition;
|
|
}
|
|
|
|
public void Attack()
|
|
{
|
|
AttackEffects();
|
|
|
|
Vector3 startPos = Scene.Camera.WorldPosition;
|
|
Vector3 dir = Scene.Camera.WorldRotation.Forward;
|
|
float maxDistance = WeaponDefinition?.Range ?? 1000f;
|
|
|
|
var tr = Scene.Trace
|
|
.Ray(startPos, startPos + dir * maxDistance)
|
|
.IgnoreGameObjectHierarchy(Dedugan.Local.GameObject)
|
|
.WithoutTags("weapon")
|
|
.UseHitboxes()
|
|
.Run();
|
|
|
|
if (tr.Hit)
|
|
{
|
|
if (tr.Hitbox != null)
|
|
{
|
|
var boneIndex = tr.Hitbox.Bone.Index;
|
|
var components = tr.GameObject.Components;
|
|
|
|
// Кэшируем компоненты для избежания повторных поисков
|
|
var dedugan = components.Get<Dedugan>();
|
|
var enemy = components.Get<Enemy>();
|
|
var hasTarget = dedugan.IsValid() || enemy.IsValid();
|
|
|
|
if (hasTarget)
|
|
{
|
|
CreateHitEffects(tr.EndPosition, tr.Normal, true);
|
|
}
|
|
|
|
if (dedugan.IsValid())
|
|
{
|
|
dedugan.ReportHit(dir, boneIndex);
|
|
}
|
|
|
|
if (enemy.IsValid())
|
|
{
|
|
enemy.ReportHit(dir, boneIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CreateHitEffects(tr.EndPosition, tr.Normal);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Rpc.Broadcast]
|
|
private void CreateHitEffects(Vector3 position, Vector3 normal, bool blood = false)
|
|
{
|
|
var rot = Rotation.LookAt(normal);
|
|
DestroyAsync(
|
|
blood
|
|
? bloodParticle.Clone(position, rot)
|
|
: particlePrefab.Clone(position, rot), 0.5f);
|
|
}
|
|
|
|
async void DestroyAsync(GameObject go, float delay)
|
|
{
|
|
await GameTask.DelaySeconds(delay);
|
|
go.Destroy();
|
|
}
|
|
|
|
[Rpc.Broadcast]
|
|
public void AttackEffects()
|
|
{
|
|
_sound?.StartSound();
|
|
MuzzleLight.Enabled = true;
|
|
GunRenderer.Set("Fire", true);
|
|
|
|
GameTask.DelaySeconds(0.05f).ContinueWith((_) =>
|
|
{
|
|
MuzzleLight.Enabled = false;
|
|
});
|
|
}
|
|
|
|
protected override void OnUse()
|
|
{
|
|
Attack();
|
|
}
|
|
}
|