using UnityEngine; using UnityEngine.Events; using MalbersAnimations.Scriptables; using MalbersAnimations.Controller; using MalbersAnimations.Events; using MalbersAnimations.Utilities; using System.Collections; using System; #if UNITY_EDITOR using UnityEditor; #endif namespace MalbersAnimations.Weapons { [System.Serializable] public class WeaponEvent : UnityEvent { } [SelectionBase] public abstract class MWeapon : MDamager, IMWeapon, IMDamager { [SerializeField] protected FloatReference minDamage = new FloatReference(10); //Weapon minimum Damage [SerializeField] protected FloatReference maxDamage = new FloatReference(20); //Weapon Max Damage [SerializeField] protected Sprite m_UI; [SerializeField] protected FloatReference minForce = new FloatReference(500); //Weapon min Force to push rigid bodies; #region Weapon Charge [SerializeField] private FloatReference chargeTime = new FloatReference(0); [SerializeField] private float chargeCharMultiplier = 1; public AnimationCurve ChargeCurve = new AnimationCurve(new Keyframe[] { new Keyframe(0, 0), new Keyframe(1, 1) }); #endregion [SerializeField] protected StringReference description = new StringReference(string.Empty); [SerializeField] protected FloatReference m_rate = new FloatReference(0); //Weapon Rate [SerializeField] protected BoolReference m_Automatic = new BoolReference(false); //Press Fire to Contiue Attacking [SerializeField] protected BoolReference m_IgnoreDraw = new BoolReference(false); //Press Fire to Contiue Attacking /// Continue Attacking using the Rate of the Weapon public bool Automatic { get => m_Automatic.Value; set => m_Automatic.Value = value; } public bool IgnoreDraw { get => m_IgnoreDraw.Value; set => m_IgnoreDraw.Value = value; } public Sprite UISprite { get => m_UI; set => m_UI = value; } #region Aiming [SerializeField] private Transform m_AimOrigin; public virtual Transform AimOrigin { get => m_AimOrigin; set => m_AimOrigin = value; } public Vector3 AimOriginPos => AimOrigin.position; [SerializeField] private AimSide m_AimSide; #endregion [SerializeField] protected WeaponID weaponType; [SerializeField] protected HolsterID holster; // From which Holder you will draw the Weapon [SerializeField] protected HolsterID holsterAnim; // From which Holder you will draw the Weapon public OldIKProfile IKProfile; public IKProfile iKProfile; public BoolReference rightHand = new BoolReference( true); // With which hand you will draw the Weapon; public Vector3 positionOffsetR; // Position Offset Right Hand public Vector3 rotationOffsetR; // Rotation Offset Right Hand public Vector3 scaleOffsetR = Vector3.one; // Rotation Offset Right Hand public Vector3 positionOffsetL; // Position Offset Left hand public Vector3 rotationOffsetL; // Rotation Offset Left Hand public Vector3 scaleOffsetL = Vector3.one; // Rotation Offset Right Hand public TransformOffset HolsterOffset = new TransformOffset(1); //Two Handed Weapon IKProperties public Vector3Reference positionOffsetIKHand; // Position Offset Left hand public Vector3Reference rotationOffsetIKHand; // Rotation Offset Left Hand public BoolReference TwoHandIK; // Makes the IK for the 2Hands public TransformReference IKHandPoint; // Rotation Offset Left Hand /// Weapon Sounds public AudioClip[] Sounds; //Sounds for the weapon public AudioSource WeaponSound; //Reference for the audio Source; private Rigidbody WeaponRB; //Reference for the audio Source; private Collider WeaponCol; //Reference for the audio Source; #region Properties /// Unique Weapon ID for each weapon public virtual int WeaponID => index; /// ID of the Damager (To be activated by the Animator) public override int Index => weaponType.ID; /// Holster the weapon can be draw from public virtual int HolsterID => (Holster != null) ? Holster.ID : 0; public HolsterID Holster { get => holster; set => holster = value; } public WeaponID WeaponType { get => weaponType; set => weaponType = value; } public int HolsterAnim => holsterAnim != null ? holsterAnim.ID : holster.ID;// { get => holsterAnim; set => holsterAnim = value; } /// Send to the Weapon Owner that the weapon Action Changed public Action WeaponAction { get; set; } private bool isEquiped = false; /// Is the Weapon Equiped public virtual bool IsEquiped { get => isEquiped; set { isEquiped = value; Debugging($"Equiped [{value}]",this); //Debug if (isEquiped && Owner) { OnEquiped.Invoke(Owner.transform); } else { Owner = null; //Clean the Owner OnUnequiped.Invoke(null); } } } /// Is the Weapon Charging? public virtual bool IsCharging { get; set; } /// Is the Weapon Reloading? public virtual bool IsReloading{ get; set; } private bool canAttack; /// Can the Weapon Attack? Uses the Weapon Rate to evaluate if the weapon can Attack Again (Works for Melee and Shotable weapons) public virtual bool CanAttack { get => canAttack; set { canAttack = value; if (!canAttack) { if (Rate > 0) StartCoroutine(DoAttackRate()); else canAttack = true; //Restore if the weapon has no Rate } //Debug.Log("Can Attack: " + canAttack); } } /// Is the Weapon Ready to Attack?? (Set by the Animations) public virtual bool IsReady { get; set; } public virtual void WeaponReady(bool value) { IsReady = value; if (IsReady) { WeaponAction?.Invoke(WA.Preparing); } Debugging($"[Weapon Ready: {IsReady}] ", this); //Debug } public IEnumerator DoAttackRate() { yield return new WaitForSeconds(Rate); canAttack = true; } /// Is the Weapon Attacking... the Opposite of CanAttack public virtual bool IsAttacking { get => !CanAttack; } /// Main Attack Input Value. Also Means the Main Attack has Started public virtual bool MainInput { get; set; } //{ // get => m_MainInput; // set // { // m_MainInput = value; // Debug.Log("MainInput: " + value); // } //} //bool m_MainInput; /// Second Attack Input Value. Also Means the Secondary Attack has Started public virtual bool SecondInput { get; set; } public string Description { get => description.Value; set => description.Value = value; } private bool isAiming; /// Is the Weapon Aiming? public virtual bool IsAiming { get => isAiming; set { isAiming = value; OnAiming.Invoke(isAiming); } } /// Side of the Camera to use when using the Weapon public AimSide AimSide { get => m_AimSide; set => m_AimSide = value; } public float MinDamage { get => minDamage.Value; set => minDamage.Value = value; } public float MaxDamage { get => maxDamage.Value; set => maxDamage.Value = value; } /// Time needed to fully charge the weapon public float ChargeTime { get => chargeTime.Value; set => chargeTime.Value = value; } /// Can the Weapon be Charged? public bool CanCharge => ChargeTime > 0; /// Charge multiplier to Apply to the Character Charge Value (For the Animator Parameter) public float ChargeCharMultiplier { get => chargeCharMultiplier; set => chargeCharMultiplier = value; } /// Elapsed Time since the Charge Weapon Started public float ChargeCurrentTime { get; set; } //{ // get => m_ChargeCurrentTime; // set // { // m_ChargeCurrentTime = value; // Debug.Log("m_ChargeCurrentTime: "+value); // } //} //float m_ChargeCurrentTime; /// Is the weapon used on the Right hand(True) or left hand (False) public bool IsRightHanded => rightHand.Value; public bool IsLefttHanded => !IsRightHanded; public Vector3 PositionOffset => IsRightHanded ? positionOffsetR : positionOffsetL; public Vector3 RotationOffset => IsRightHanded ? rotationOffsetR : rotationOffsetL; public Vector3 ScaleOffset => IsRightHanded ? scaleOffsetR : scaleOffsetL; /// Minimun Force the Weapon can do to a Rigid Body public float MinForce { get => minForce.Value; set => minForce.Value = value; } /// Maximun Force the Weapon can do to a Rigid Body public float MaxForce { get => m_Force.Value; set => m_Force.Value = value; } /// Weapon Rate public float Rate { get => m_rate.Value; set => m_rate.Value = value; } ///// Is the weapon fully charged? //public bool IsCharged => ChargeCurrentTime >= ChargeTime; /// Normalized Value for the Charge. if ChargeTime == 0 then Random Value between [0-1] public float ChargedNormalized => CanCharge ? ChargeCurve.Evaluate(Mathf.Clamp01(ChargeCurrentTime / ChargeTime)) : UnityEngine.Random.Range(0f, 1f); /// Normalized Value of the Charge public float Power => Mathf.Lerp(MinForce, MaxForce, ChargedNormalized); /// Enable or Disable the weapon to "block it" public override bool Active { get => enabled; set { m_Active.Value = enabled = value; Debugging($"Active [{value}]", this); //If the weapon is Disabled change the Weapon to Idle (if it Was Aiming or Shooting or Something like that if (!value && IsEquiped) WeaponAction?.Invoke(WA.Idle); } } public IMWeaponOwner WeaponOwner { get; set; } #endregion #region Events public TransformEvent OnEquiped = new TransformEvent(); public TransformEvent OnUnequiped = new TransformEvent(); /// Invoked when the weapon is Charging (Returns a Normalized Value) public FloatEvent OnCharged = new FloatEvent(); public FloatEvent OnChargedFinished = new FloatEvent(); public BoolEvent OnAiming = new BoolEvent(); // public UnityEvent OnPlaced = new UnityEvent(); #endregion /// Returns True if the Weapons has the same ID public override bool Equals(object a) { if (a is IMWeapon) return WeaponID == (a as IMWeapon).WeaponID; return false; } public override int GetHashCode() => base.GetHashCode(); #region WeaponActions /// Set the Primary Attack internal virtual void MainAttack_Start(IMWeaponOwner RC) { MainInput = true; SecondInput = false; ResetCharge(); } /// Set when the Current Attack is Active and Holding ... So reset the Attack internal virtual void Attack_Charge(IMWeaponOwner RC, float time) { if (Automatic && CanAttack && Rate > 0) { if (MainInput) MainAttack_Start(RC); else if (SecondInput) SecondaryAttack_Start(RC); } } /// Set when the Primary Attack is Released (BOW) internal virtual void MainAttack_Released() { Debugging($"Main Attack Released",this); MainInput = false; ResetCharge(); } /// Set the Secondary Attack internal virtual void SecondaryAttack_Start(IMWeaponOwner RC) { // Debugging($"2nd Attack Started"); SecondInput = true; MainInput = false; ResetCharge(); } /// Set when the Secondary Attack is Released (BOW) internal virtual void SecondaryAttack_Released() { // Debugging($"2nd Attack Released"); SecondInput = false; ResetCharge(); } /// Reload Weapon internal virtual void Reload(IMWeaponOwner RC) { } /// Called on the Late Update of the Rider Combat Script internal virtual void LateUpdateWeaponIK(IMWeaponOwner RC) { IKProfile?.LateUpdate_IK(RC); } /// Called on the Late Update of the Rider Combat Script internal virtual void LateWeaponModification(IMWeaponOwner RC) { } internal virtual void OnAnimatorWeaponIK(IMWeaponOwner RC) { IKProfile?.OnAnimator_IK(RC); iKProfile?.ApplyOffsets(RC.Anim, RC.AimDirection, 1); } internal virtual void TwoWeaponIK(IMWeaponOwner RC) { if (TwoHandIK) { var ikGoal = !IsRightHanded ? AvatarIKGoal.RightHand : AvatarIKGoal.LeftHand; //Set the IK goal acording the Right or Left Hand var Weight = 1; RC.Anim.SetIKPosition(ikGoal, IKHandPoint.position); RC.Anim.SetIKPositionWeight(ikGoal, Weight); RC.Anim.SetIKRotation(ikGoal, IKHandPoint.rotation); RC.Anim.SetIKRotationWeight(ikGoal, Weight); } } /// Reload Weapon public virtual bool Reload() { return false; } #endregion #region ABILITY SYSTEM /// Prepare weapon with all the necesary component to activate on the Weapons Owner (SAME AS START ABILITY) public virtual bool PrepareWeapon(IMWeaponOwner _char) { if (gameObject.IsPrefab()) return false; //Means is still a prefab WeaponOwner = _char; Owner = _char.Owner; IsEquiped = true; CanAttack = true; ChargeCurrentTime = 0; IgnoreTransform = _char.IgnoreTransform; Active = true; animator = _char.Anim; //Set the Animator; DisablePhysics(); Debugging($"Weapon [Prepared]",this); return true; } /// Attack Trigger Behaviour public virtual void ActivateDamager(int value) { } /// Charge the Weapon using time.deltatime public virtual void Charge(float time) { if (CanCharge) { ChargeCurrentTime += time; IsCharging = true; OnCharged.Invoke(ChargedNormalized); //Charge Normalized } else { ReleaseCharge(); //Means the weapon does not need charging } } /// Reset the Charge of the weapon public virtual void ResetCharge() { if (CanCharge) { ChargeCurrentTime = 0; IsCharging = false; OnCharged.Invoke(0); Debugging($"Weapon [Charge Reseted]",this); } } /// Set when the Primary Attack is Released (BOW) public virtual void ReleaseCharge() { WeaponAction?.Invoke(WA.Release); ResetCharge(); } #endregion /// Resets all the Weapon Properties public virtual void ResetWeapon() { Owner = null; WeaponOwner = null; IsEquiped = false; IsAiming = false; animator = null; IgnoreTransform = null; ResetCharge(); Debugging($"Weapon [Reseted]",this); } public virtual void Initialize() { IsEquiped = false; if (Owner == null) Owner = transform.root.gameObject; if (!WeaponSound) WeaponSound = gameObject.FindComponent(); //Gets the Weapon Source if (!WeaponSound) WeaponSound = gameObject.AddComponent(); //Create an AudioSourse if theres no Audio Source on the weapon WeaponSound.spatialBlend = 1; WeaponRB = GetComponent(); //Gets the Weapon Rigid Body WeaponCol = GetComponent(); //Gets the Weapon Collider if (holsterAnim == null) holsterAnim = holster; } /// Apply the Correct offset to the weapon public virtual void ApplyOffset() { transform.localPosition = PositionOffset; //Set the Correct Position transform.localEulerAngles = RotationOffset; //Set the Correct Rotation transform.localScale = ScaleOffset; //Set the Correct Scale } public void DisablePhysics() { if (WeaponRB) { WeaponRB.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative; WeaponRB.isKinematic = true; //IMPORTANT } if (WeaponCol) WeaponCol.enabled = false; } /// CallBack from the RiderCombat Layer in the Animator to reproduce a sound on the weapon public virtual void PlaySound(int ID) { if (ID < Sounds.Length && Sounds[ID] != null) { var newSound = Sounds[ID]; if (WeaponSound && !playingSound && gameObject.activeInHierarchy) { playingSound = true; //HACK FOR THE SOUND this.Delay_Action(2, () => { WeaponSound.PlayOneShot(newSound); playingSound = false; } ); } } } protected bool playingSound; /// This is used to listen the Animator asociated to this gameObject public virtual bool OnAnimatorBehaviourMessage(string message, object value) => this.InvokeWithParams(message, value); #if UNITY_EDITOR protected override void Reset() { base.Reset(); index = UnityEngine.Random.Range(100000, 999999); WeaponSound = GetComponent(); //Gets the Weapon Source if (!WeaponSound) WeaponSound = gameObject.AddComponent(); //Create an AudioSourse if theres no Audio Source on the weapon WeaponSound.spatialBlend = 1; holster = MTools.GetInstance("Back Holster 1"); } #endif [HideInInspector] public int Editor_Tabs1; [HideInInspector] public int Editor_Tabs2; } #region INSPECTOR #if UNITY_EDITOR public abstract class MWeaponEditor : MDamagerEd { protected string SoundHelp; protected SerializedProperty Sounds, WeaponSound, weaponType, rightHand, StatID, mod, ChargeTime, chargeCharMultiplier, MaxChargeDamage, m_AimOrigin, m_UI, m_AimSide, OnCharged, OnUnequiped, OnEquiped, /*OnPlaced, */minDamage, maxDamage, minForce, holster, holsterAnim, IKProfile, iKProfile, Rate, TwoHandIK, IKHandPoint, rotationOffsetIKHand, positionOffsetIKHand, OnAiming, m_Automatic, ChargeCurve, HolsterOffset, description, Editor_Tabs2, Editor_Tabs1, rotationOffsetR, positionOffsetR, rotationOffsetL, positionOffsetL, scaleOffsetR, scaleOffsetL, m_IgnoreDraw; bool offsets = true; protected string WeaponTab = "Weapon"; protected string[] Tabs1 = new string[] { "General", "Damage", "IK", "Extras" }; protected string[] Tabs2 = new string[] { "Weapon", "Sounds", "Events" }; protected MWeapon mWeapon; protected virtual void SetOnEnable() { mWeapon = (MWeapon)target; FindBaseProperties(); Tabs2[0] = WeaponTab; Sounds = serializedObject.FindProperty("Sounds"); m_UI = serializedObject.FindProperty("m_UI"); WeaponSound = serializedObject.FindProperty("WeaponSound"); weaponType = serializedObject.FindProperty("weaponType"); HolsterOffset = serializedObject.FindProperty("HolsterOffset"); description = serializedObject.FindProperty("description"); m_Automatic = serializedObject.FindProperty("m_Automatic"); m_AimOrigin = serializedObject.FindProperty("m_AimOrigin"); chargeCharMultiplier = serializedObject.FindProperty("chargeCharMultiplier"); rightHand = serializedObject.FindProperty("rightHand"); minDamage = serializedObject.FindProperty("minDamage"); maxDamage = serializedObject.FindProperty("maxDamage"); minForce = serializedObject.FindProperty("minForce"); m_IgnoreDraw = serializedObject.FindProperty("m_IgnoreDraw"); IKProfile = serializedObject.FindProperty("IKProfile"); iKProfile = serializedObject.FindProperty("iKProfile"); OnCharged = serializedObject.FindProperty("OnCharged"); OnUnequiped = serializedObject.FindProperty("OnUnequiped"); OnEquiped = serializedObject.FindProperty("OnEquiped"); OnAiming = serializedObject.FindProperty("OnAiming"); // OnPlaced = serializedObject.FindProperty("OnPlaced"); holster = serializedObject.FindProperty("holster"); holsterAnim = serializedObject.FindProperty("holsterAnim"); rotationOffsetR = serializedObject.FindProperty("rotationOffsetR"); rotationOffsetL = serializedObject.FindProperty("rotationOffsetL"); positionOffsetR = serializedObject.FindProperty("positionOffsetR"); positionOffsetL = serializedObject.FindProperty("positionOffsetL"); scaleOffsetR = serializedObject.FindProperty("scaleOffsetR"); scaleOffsetL = serializedObject.FindProperty("scaleOffsetL"); ChargeTime = serializedObject.FindProperty("chargeTime"); MaxChargeDamage = serializedObject.FindProperty("MaxChargeDamage"); ChargeCurve = serializedObject.FindProperty("ChargeCurve"); m_AimSide = serializedObject.FindProperty("m_AimSide"); Rate = serializedObject.FindProperty("m_rate"); Editor_Tabs1 = serializedObject.FindProperty("Editor_Tabs1"); Editor_Tabs2 = serializedObject.FindProperty("Editor_Tabs2"); StatID = statModifier.FindPropertyRelative("ID"); mod = statModifier.FindPropertyRelative("modify"); TwoHandIK = serializedObject.FindProperty("TwoHandIK"); IKHandPoint = serializedObject.FindProperty("IKHandPoint"); rotationOffsetIKHand = serializedObject.FindProperty("rotationOffsetIKHand"); positionOffsetIKHand = serializedObject.FindProperty("positionOffsetIKHand"); } protected virtual void WeaponInspector(bool showAim = true) { Editor_Tabs1.intValue = GUILayout.Toolbar(Editor_Tabs1.intValue, Tabs1); if (Editor_Tabs1.intValue != Tabs1.Length) Editor_Tabs2.intValue = Tabs2.Length; Editor_Tabs2.intValue = GUILayout.Toolbar(Editor_Tabs2.intValue, Tabs2); if (Editor_Tabs2.intValue != Tabs2.Length) Editor_Tabs1.intValue = Tabs1.Length; //First Tabs int Selection = Editor_Tabs1.intValue; if (Selection == 0) DrawWeapon(showAim); else if (Selection == 1) DrawDamage(); else if (Selection == 2) DrawIKWeapon(); else if (Selection == 3) DrawExtras(); //2nd Tabs Selection = Editor_Tabs2.intValue; if (Selection == 0) DrawAdvancedWeapon(); else if (Selection == 1) DrawSound(); else if (Selection == 2) DrawEvents(); } protected virtual void DrawExtras() { EditorGUILayout.BeginVertical(EditorStyles.helpBox); { minForce.isExpanded = MalbersEditor.Foldout(minForce.isExpanded, "Physics Force"); if (minForce.isExpanded) { // EditorGUILayout.BeginHorizontal(); { // EditorGUIUtility.labelWidth = 50; EditorGUILayout.PropertyField(minForce, new GUIContent("Min", "Minimun Force to apply to a hitted rigid body")); EditorGUILayout.PropertyField(Force, new GUIContent("Max", "Maximun Force to apply to a hitted rigid body")); // EditorGUIUtility.labelWidth = 0; } // EditorGUILayout.EndHorizontal(); EditorGUILayout.PropertyField(forceMode); } } EditorGUILayout.EndVertical(); DrawMisc(); EditorGUILayout.BeginVertical(EditorStyles.helpBox); EditorGUILayout.PropertyField(description); EditorGUILayout.EndVertical(); } protected virtual void DrawDamage() { EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.PropertyField(Rate, new GUIContent("Rate", "Time(Delay) between attacks")); EditorGUILayout.PropertyField(m_Automatic, new GUIContent("Automatic", "Continues Attacking if the Main Attack Input is pressed")); EditorGUILayout.PropertyField(ChargeTime, new GUIContent("Charge Time", "Weapons can be Charged|Hold before releasing the Attack.")); if (mWeapon.ChargeTime > 0) { EditorGUILayout.PropertyField(chargeCharMultiplier, new GUIContent("Charge Char Mult", "Charge multiplier to Apply to the Character Charge Value (For the Animator Parameter) ")); EditorGUILayout.PropertyField(ChargeCurve, new GUIContent("Curve", "Evaluation of the Charge in a Curve")); } else EditorGUILayout.HelpBox("When [Charge Time] is 0 the 'Charge Weapon' logic will be ignored", MessageType.Warning); } EditorGUILayout.EndVertical(); DrawCriticalDamage(); EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.LabelField("Modify Stat", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); { EditorGUIUtility.labelWidth = 50; EditorGUILayout.PropertyField(StatID, new GUIContent("Stat")); EditorGUILayout.PropertyField(mod, GUIContent.none, GUILayout.MinWidth(50), GUILayout.MaxWidth(120)); EditorGUIUtility.labelWidth = 0; } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { EditorGUIUtility.labelWidth = 50; EditorGUILayout.PropertyField(minDamage, new GUIContent("Min", "Minimun Damage")); EditorGUILayout.PropertyField(maxDamage, new GUIContent("Max", "Minimun Damage")); EditorGUIUtility.labelWidth = 0; } EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); } protected virtual void DrawWeapon(bool showAim = true) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(m_Active); MalbersEditor.DrawDebugIcon(debug); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { EditorGUILayout.PropertyField(index, new GUIContent("Index", "Unique Weapon ID for each weapon"), GUILayout.MinWidth(1)); if (GUILayout.Button("Generate", EditorStyles.miniButton, GUILayout.MaxWidth(70))) index.intValue = UnityEngine.Random.Range(100000, 999999); } EditorGUILayout.EndHorizontal(); CheckWeaponID(); EditorGUILayout.LabelField("Layer Interaction", EditorStyles.boldLabel); EditorGUILayout.PropertyField(hitLayer); EditorGUILayout.PropertyField(triggerInteraction); EditorGUILayout.PropertyField(dontHitOwner, new GUIContent("Don't hit Owner")); if (mWeapon.dontHitOwner.Value) EditorGUILayout.PropertyField(owner); } EditorGUILayout.EndVertical(); EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.PropertyField(weaponType, new GUIContent("Type", "Gets the Weapon Type ID, Used on the Animator to Play the Matching animation for the weapon")); EditorGUILayout.PropertyField(holster, new GUIContent("Holster", "The Side where the weapon is Draw/Store from")); EditorGUILayout.PropertyField(holsterAnim, new GUIContent("Holster Anim?", "Use Diferent Animation for Draw/Store")); //EditorGUILayout.PropertyField(m_UI, new GUIContent("UI", "Sprite to be represented on the UI")); EditorGUILayout.PropertyField(m_IgnoreDraw, new GUIContent("Ignore Draw", "Ignores Draw and Store Animations when equipping a weapon")); } EditorGUILayout.EndVertical(); if (showAim) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.PropertyField(m_AimSide, new GUIContent("Aim Side", "Side of the Character the Weapon will aim when Aim is true")); if (m_AimSide.intValue != 0) EditorGUILayout.PropertyField(m_AimOrigin, new GUIContent("Aim Origin", "Point where the Aiming will be Calculated.\nAlso for Shootable weapons the point where the Projectiles will come out")); } EditorGUILayout.EndVertical(); } EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.PropertyField(rightHand); EditorGUILayout.HelpBox("The Weapon is " + (mWeapon.IsRightHanded ? "Right Handed" : "Left Handed"), MessageType.Info); } EditorGUILayout.EndVertical(); EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUI.indentLevel++; offsets = EditorGUILayout.Foldout(offsets, "Offset " + (mWeapon.IsRightHanded? "Right Hand" : "Left Hand")); EditorGUI.indentLevel--; if (offsets) { EditorGUI.indentLevel++; EditorGUI.indentLevel++; EditorGUILayout.PropertyField(mWeapon.IsRightHanded ? positionOffsetR : positionOffsetL, new GUIContent("Position")); EditorGUILayout.PropertyField(mWeapon.IsRightHanded ? rotationOffsetR : rotationOffsetL, new GUIContent("Rotation")); EditorGUILayout.PropertyField(mWeapon.IsRightHanded ? scaleOffsetR : scaleOffsetL, new GUIContent("Scale")); if (Application.isPlaying && mWeapon.IsEquiped && GUILayout.Button("Store Offset Values ")) { if (mWeapon.IsRightHanded) { positionOffsetR.vector3Value = mWeapon.transform.localPosition; rotationOffsetR.vector3Value = mWeapon.transform.localEulerAngles.Round(); } else { positionOffsetL.vector3Value = mWeapon.transform.localPosition; rotationOffsetL.vector3Value = mWeapon.transform.localEulerAngles.Round(); } } //using (var cc = new EditorGUI.ChangeCheckScope()) //{ // if (cc.changed) // { // if (Application.isPlaying && mWeapon.IsEquiped) // { // mWeapon.ApplyOffset(); // } // //Undo.RecordObject(target, "Move Handles"); // } //} //EditorGUI.indentLevel--; //EditorGUI.indentLevel--; } EditorGUI.indentLevel++; EditorGUILayout.PropertyField(HolsterOffset, true); EditorGUI.indentLevel--; } EditorGUILayout.EndVertical(); //EditorGUILayout.PropertyField(debug); } protected virtual void DrawIKWeapon() { EditorGUILayout.BeginVertical(EditorStyles.helpBox); { IKProfile.isExpanded = MalbersEditor.Foldout(IKProfile.isExpanded, "On Animator IK"); if (IKProfile.isExpanded) { EditorGUILayout.PropertyField(IKProfile, new GUIContent("IK Profile (Old)", "IK Modification to the Character Body to Aim Properly")); EditorGUILayout.PropertyField(iKProfile, new GUIContent("IK Profile", "IK Modification to the Character Body to Aim Properly")); } } EditorGUILayout.EndVertical(); EditorGUILayout.BeginVertical(EditorStyles.helpBox); { TwoHandIK.isExpanded = MalbersEditor.Foldout(TwoHandIK.isExpanded, "Two Handed Weapon"); if (TwoHandIK.isExpanded) { EditorGUILayout.PropertyField(TwoHandIK); if (mWeapon.TwoHandIK.Value) { EditorGUILayout.LabelField("(The " + (mWeapon.IsRightHanded ? "Left Hand" : "Right Hand") + " is the auxiliar Hand)"); EditorGUILayout.PropertyField(IKHandPoint); EditorGUILayout.PropertyField(positionOffsetIKHand); EditorGUILayout.PropertyField(rotationOffsetIKHand); } } } EditorGUILayout.EndVertical(); } protected virtual void DrawAdvancedWeapon() { } protected virtual void DrawSound() { EditorGUILayout.BeginVertical(EditorStyles.helpBox); // EditorGUILayout.LabelField("Sound", EditorStyles.boldLabel); EditorGUILayout.PropertyField(WeaponSound, new GUIContent("Weapon Source", "Audio Source for the wapons")); EditorGUI.indentLevel++; UpdateSoundHelp(); EditorGUILayout.PropertyField(Sounds, new GUIContent("Sounds", "Sounds Played by the weapon"), true); EditorGUI.indentLevel--; EditorGUILayout.HelpBox(SoundHelp, MessageType.None); EditorGUILayout.EndVertical(); } protected override void DrawCustomEvents() { // EditorGUILayout.PropertyField(OnPlaced, new GUIContent("On Placed [In Holster or Invectory] ")); EditorGUILayout.PropertyField(OnEquiped, new GUIContent("On Equiped")); EditorGUILayout.PropertyField(OnUnequiped, new GUIContent("On Unequiped")); EditorGUILayout.PropertyField(OnCharged, new GUIContent("On Charged Weapon")); EditorGUILayout.PropertyField(OnAiming, new GUIContent("On Aiming")); ChildWeaponEvents(); } protected virtual string CustomEventsHelp() { return ""; } protected virtual void ChildWeaponEvents() { } protected virtual void UpdateSoundHelp() { } protected void CheckWeaponID() { if (index.intValue == 0) EditorGUILayout.HelpBox("Weapon ID needs cant be Zero, Please Set an ID number ", MessageType.Warning); } } #endif #endregion }