91 lines
3.0 KiB
C#
91 lines
3.0 KiB
C#
|
|
using OTGIntegrated.Combat;
|
||
|
|
using OTGIntegrated.Stats;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
namespace OTGIntegrated.Weapons
|
||
|
|
{
|
||
|
|
public sealed class WeaponController : MonoBehaviour
|
||
|
|
{
|
||
|
|
public Transform attackOrigin;
|
||
|
|
public LayerMask hitMask = ~0;
|
||
|
|
[SerializeField] private float meleeRadius = 0.7f;
|
||
|
|
|
||
|
|
private readonly Collider[] hits = new Collider[16];
|
||
|
|
|
||
|
|
public bool Attack(WeaponData weapon, PlayerStats stats)
|
||
|
|
{
|
||
|
|
if (weapon == null || stats == null)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
Transform origin = attackOrigin != null ? attackOrigin : transform;
|
||
|
|
Vector3 start = origin.position + Vector3.up * 0.8f;
|
||
|
|
Vector3 forward = origin.forward;
|
||
|
|
forward.y = 0f;
|
||
|
|
forward = forward.sqrMagnitude > 0.001f ? forward.normalized : transform.forward;
|
||
|
|
|
||
|
|
float finalDamage = weapon.damage + stats.Damage;
|
||
|
|
bool critical = Random.value < stats.CriticalChance;
|
||
|
|
if (critical)
|
||
|
|
{
|
||
|
|
finalDamage *= 1.75f;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (weapon.isRanged)
|
||
|
|
{
|
||
|
|
if (Physics.Raycast(start, forward, out RaycastHit hit, weapon.range, hitMask, QueryTriggerInteraction.Ignore))
|
||
|
|
{
|
||
|
|
return ApplyDamage(hit.collider, finalDamage, critical);
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
Vector3 center = start + forward * Mathf.Max(0.6f, weapon.range * 0.55f);
|
||
|
|
int count = Physics.OverlapSphereNonAlloc(center, meleeRadius + weapon.range * 0.12f, hits, hitMask, QueryTriggerInteraction.Ignore);
|
||
|
|
bool damaged = false;
|
||
|
|
for (int i = 0; i < count; i++)
|
||
|
|
{
|
||
|
|
Collider hit = hits[i];
|
||
|
|
if (hit == null || hit.transform == transform || hit.GetComponentInParent<PlayerStats>() != null)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (ApplyDamage(hit, finalDamage, critical))
|
||
|
|
{
|
||
|
|
damaged = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return damaged;
|
||
|
|
}
|
||
|
|
|
||
|
|
private bool ApplyDamage(Collider collider, float amount, bool critical)
|
||
|
|
{
|
||
|
|
Damageable damageable = collider.GetComponentInParent<Damageable>();
|
||
|
|
if (damageable == null || !damageable.IsAlive)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
damageable.TakeDamage(amount, gameObject);
|
||
|
|
if (critical)
|
||
|
|
{
|
||
|
|
OTGIntegrated.Core.GameEvents.RaiseNotification("Критический удар");
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnDrawGizmosSelected()
|
||
|
|
{
|
||
|
|
Gizmos.color = new Color(1f, 0.45f, 0.1f, 0.25f);
|
||
|
|
Transform origin = attackOrigin != null ? attackOrigin : transform;
|
||
|
|
Gizmos.DrawWireSphere(origin.position + origin.forward * 1.3f + Vector3.up * 0.8f, meleeRadius);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|