Weapons/Base/BaseWeapon.cs
using Opium;

/// <summary>
/// The base implementation of all weapons. There shouldn't be much in this class to begin with.
/// </summary>
public abstract partial class BaseWeapon : BaseInteract
{
	/// <summary>
	/// Holds a reference to the view model's gameobject (a prefab hopefully) and creates it on the player's camera
	/// </summary>
	[Property, Category( "Prefabs" )] public GameObject ViewModelPrefab { get; set; }

	/// <summary>
	/// The weapon's world model (if any)
	/// </summary>
	[Property] public SkinnedModelRenderer WorldModel { get; set; }

	/// <summary>
	/// When dropping the object, we want this to spawn
	/// </summary>
	[Property, Category( "Prefabs" )] public GameObject PickupPrefab { get; set; }

	[Property] public bool Droppable { get; set; } = true;

	public override bool ShowInteractionUI => true;

	[Property] public GameObject ViewModel { get; set; }

	/// <summary>
	/// How quickly we can attack
	/// </summary>
	[Property] public float BaseShootRate { get; set; }

	[Property] public float StaminaDrain { get; set; } = 0f;

	/// <summary>
	/// Generic event listener, doesn't pass any extra info.
	/// </summary>
	public Action<string> EventListener { get; set; }

	/// <summary>
	/// Time since we have attacked
	/// </summary>
	public TimeSince TimeSinceShoot { get; set; } = 10;

	/// <summary>
	/// Time since we aiming
	/// </summary>
	public TimeSince TimeSinceAim { get; set; } = 10;

	/// <summary>
	/// Damage
	/// </summary>
	[Property] public float BaseDamage { get; set; } = 25f;

	/// <summary>
	/// Damage?
	/// </summary>
	/// <param name="info"></param>
	/// <returns></returns>
	protected virtual void CalculateDamage( in Sandbox.DamageInfo info )
	{
		var dmg = info.Damage;
		if ( info.Hitbox?.Tags.Has( "head" ) ?? false )
		{
			dmg *= 3.0f;
		}

		info.Damage = dmg;
	}

	public Actor Actor { get; set; }

	/// <summary>
	/// Set the weapon as active?
	/// </summary>
	/// <param name="active"></param>
	public void SetAsActive( bool active )
	{
		Actor.SetupViewModel( this, active );

		if ( WorldModel.IsValid() )
		{
			WorldModel.GameObject.Enabled = false;
		}

		GameObject.Enabled = active;
	}

	/// <summary>
	/// Can we attack?
	/// </summary>
	/// <returns></returns>
	public virtual bool CanShoot()
	{
		if ( !Actor.CanShoot( this ) ) return false;

		return TimeSinceShoot >= GetShootRate();
	}

	/// <summary>
	/// Gets the attack rate, child components can override this, stuff like stats?
	/// </summary>
	/// <returns></returns>
	protected virtual float GetShootRate()
	{
		return BaseShootRate;
	}

	/// <summary>
	/// Called when attacking with this weapon.
	/// </summary>
	public virtual void Shoot()
	{
		TimeSinceShoot = 0;
	}

	public virtual void OnCreateViewModel()
	{
		//
	}

	public virtual void OnDamage( in Sandbox.DamageInfo damage )
	{
		//
	}

	public virtual void Aim()
	{
		TimeSinceAim = 0;
	}

	public virtual bool CanAim()
	{
		return false;
	}

	/// <summary>
	/// Gets a surface from a trace. Trying to find a SurfaceComponent before using the one from the model.
	/// </summary>
	/// <param name="tr"></param>
	/// <returns></returns>
	[Obsolete( "Let's make surfaces not used here" )]
	protected Surface GetSurfaceFromTrace( SceneTraceResult tr )
	{
		return tr.Surface;
	}
}