You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

285 lines
10 KiB
C#

3 years ago
using UnityEngine;
using System.Collections.Generic;
using MalbersAnimations.Events;
using MalbersAnimations.Utilities;
using UnityEngine.Events;
using MalbersAnimations.Scriptables;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace MalbersAnimations.Weapons
{
[AddComponentMenu("Malbers/Weapons/Melee Weapon")]
public class MMelee : MWeapon
{
[RequiredField] public Collider meleeTrigger;
public BoolEvent OnCauseDamage = new BoolEvent();
public Color DebugColor = new Color(1, 0.25f, 0, 0.5f);
public bool UseCameraSide;
public bool InvertCameraSide;
public int Attacks = 1;
protected bool canCauseDamage; //The moment in the Animation the weapon can cause Damage
public bool CanCauseDamage
{
get => canCauseDamage;
set
{
Debugging($"Can cause Damage [{value}]",this);
canCauseDamage = value;
proxy.Active = value;
meleeTrigger.enabled = value; //Enable/Disable the Trigger
}
}
protected TriggerProxy proxy { get; private set; }
/// <summary>Damager from the Attack Triger Behaviour</summary>
public override void ActivateDamager(int value)
{
if (value == 0)
{
CanCauseDamage = false;
OnCauseDamage.Invoke(CanCauseDamage);
}
else if (value == -1 || value == Index)
{
CanCauseDamage = true;
OnCauseDamage.Invoke(CanCauseDamage);
}
}
public override void DoDamage(bool value)
{
ActivateDamager(value ? -1 : 0);
}
private void Awake()
{
if (animator)
defaultAnimatorSpeed = animator.speed;
Initialize();
}
public override void Initialize()
{
base.Initialize();
FindTrigger();
}
void OnEnable()
{
if (proxy)
{
proxy.EnterTriggerInteraction += AttackTriggerEnter;
proxy.ExitTriggerInteraction += AttackTriggerExit;
}
CanCauseDamage = false;
}
/// <summary>Disable Listeners </summary>
void OnDisable()
{
if (proxy)
{
proxy.EnterTriggerInteraction -= AttackTriggerEnter;
proxy.ExitTriggerInteraction -= AttackTriggerExit;
}
}
#region Main Attack
internal override void MainAttack_Start(IMWeaponOwner RC)
{
base.MainAttack_Start(RC);
if (CanAttack)
{
ResetCharge();
var Side = UseCameraSide && (InvertCameraSide ? RC.AimingSide : !RC.AimingSide);
RiderMeleeAttack(Side);
}
}
internal override void SecondaryAttack_Start(IMWeaponOwner RC)
{
MainInput = false;
SecondInput = true;
if (CanAttack)
{
DoDamage(false);
ResetCharge();
if (!UseCameraSide) RiderMeleeAttack(true); //Attack with Left Hand
}
}
/// <summary>Set all parameters for Melee Attack </summary>
/// <param name="rightSide">true = Right Side of the ount.. false = Left Side of the ount</param>
protected virtual void RiderMeleeAttack(bool rightSide)
{
int attackID = Random.Range(1, Attacks + 1) * (rightSide ? 1 : -1); // Set the Attacks for the RIGHT Side with the 'Right Hand' 1 2
WeaponAction?.Invoke(attackID); //Convert into Left attack if the weapon is Left Handed
CanAttack = false;
}
#endregion
void AttackTriggerEnter(GameObject root, Collider other)
{
// if (IsInvalid(other)) return; //Check Layers and Don't hit yourself
if (other.transform.root == IgnoreTransform) return; //Check an Extra transform that you cannot hit...e.g your mount
var damagee = other.GetComponentInParent<IMDamage>(); //Get the Animal on the Other collider
var center = meleeTrigger.bounds.center;
Direction = (other.bounds.center - center).normalized; //Calculate the direction of the attack
TryInteract(other.gameObject); //Get the interactable on the Other collider
TryPhysics(other.attachedRigidbody, other, center, Direction, Force); //If the other has a riggid body and it can be pushed
TryStopAnimator();
TryHit(other, meleeTrigger.bounds.center);
var Damage = new StatModifier(statModifier)
{ Value = Mathf.Lerp(MinDamage, MaxDamage, ChargedNormalized) }; //Do the Damage depending the charge
TryDamage(damagee, Damage); //if the other does'nt have the Damagable Interface dont send the Damagable stuff
}
void AttackTriggerExit(GameObject root, Collider other)
{
//???
}
public override void ResetWeapon()
{
meleeTrigger.enabled = false;
proxy.Active = false;
base.ResetWeapon();
}
private void FindTrigger()
{
if (meleeTrigger == null) meleeTrigger = GetComponent<Collider>();
if (meleeTrigger)
{
proxy = TriggerProxy.CheckTriggerProxy(meleeTrigger, Layer, TriggerInteraction, Owner.transform);
meleeTrigger.enabled = false;
proxy.Active = meleeTrigger.enabled;
}
else
{
Debug.LogError($"Weapon [{name}] needs a collider. Please add one. Disabling Weapon", this);
enabled = false;
}
}
#if UNITY_EDITOR
void OnDrawGizmos()
{
if (meleeTrigger)
{
MTools.DrawTriggers(meleeTrigger.transform, meleeTrigger, DebugColor);
}
}
protected override void Reset()
{
base.Reset();
weaponType = MTools.GetInstance<WeaponID>("Melee");
m_rate.Value = 0.5f;
m_Automatic.Value = true;
}
//[ContextMenu("Create Cinemachine Impulse")]
//void CreateCinemachinePulse()
//{
// var cinemachinePulse = GetComponent<Cinemachine.CinemachineImpulseSource>();
// if (cinemachinePulse == null)
// {
// cinemachinePulse = gameObject.AddComponent<Cinemachine.CinemachineImpulseSource>();
// MTools.SetDirty(gameObject);
// }
// cinemachinePulse.m_DefaultVelocity = Vector3.up * 0.1f;
// cinemachinePulse.m_ImpulseDefinition.m_ImpulseType = Cinemachine.CinemachineImpulseDefinition.ImpulseTypes.Uniform;
// cinemachinePulse.m_ImpulseDefinition.m_ImpulseShape = Cinemachine.CinemachineImpulseDefinition.ImpulseShapes.Bump;
// cinemachinePulse.m_ImpulseDefinition.m_ImpulseDuration = 0.2f;
// UnityEditor.Events.UnityEventTools.AddVoidPersistentListener(OnHit, cinemachinePulse.GenerateImpulse);
// MTools.SetDirty(cinemachinePulse);
//}
#endif
}
#if UNITY_EDITOR
[CanEditMultipleObjects, CustomEditor(typeof(MMelee))]
public class MMeleeEditor : MWeaponEditor
{
SerializedProperty meleeCollider, OnCauseDamage, UseCameraSide, InvertCameraSide, Attacks;
void OnEnable()
{
WeaponTab = "Melee";
SetOnEnable();
meleeCollider = serializedObject.FindProperty("meleeTrigger");
OnCauseDamage = serializedObject.FindProperty("OnCauseDamage");
InvertCameraSide = serializedObject.FindProperty("InvertCameraSide");
UseCameraSide = serializedObject.FindProperty("UseCameraSide");
Attacks = serializedObject.FindProperty("Attacks");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
DrawDescription("Melee Weapon Properties");
if (meleeCollider.objectReferenceValue == null)
EditorGUILayout.HelpBox("Weapon needs a collider. Check [Melee] Tab", MessageType.Error);
WeaponInspector();
serializedObject.ApplyModifiedProperties();
}
protected override void UpdateSoundHelp()
{
SoundHelp = "0:Draw 1:Store 2:Swing 3:Hit \n (Leave 3 Empty, add SoundByMaterial and Invoke 'PlayMaterialSound' for custom Hit sounds)";
}
protected override void ChildWeaponEvents()
{
EditorGUILayout.PropertyField(OnCauseDamage, new GUIContent("On AttackTrigger Active"));
}
protected override void DrawAdvancedWeapon()
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.PropertyField(meleeCollider, new GUIContent("Melee Trigger", "Gets the reference of where is the Melee Collider of this weapon (Not Always is in the same gameobject level)"));
EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.LabelField("Riding Behaviour", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(Attacks, new GUIContent("Attacks", "Amount of Attack Animations can do on both sides while mounting"));
EditorGUILayout.PropertyField(UseCameraSide, new GUIContent("Use Camera Side", "The Attacks are Activated by the Main Attack and It uses the Side of the Camera to Attack on the Right or the Left side of the Mount"));
if (UseCameraSide.boolValue)
EditorGUILayout.PropertyField(InvertCameraSide, new GUIContent("Invert Camera Side", "Inverts the camera side value"));
EditorGUILayout.EndVertical();
}
}
#endif
}