#if INVECTOR_PLAYABLESANIMATOR
using System.Collections.Generic;
using InvectorCore.Playables;
using UnityEngine;
namespace Invector.vMelee
{
using vEventSystems;
///
/// PlayablesAnimator counterpart of .
/// Serialized field names match the Animator behaviour so the PDM Animator Controller
/// conversion copies the authored values over automatically.
///
public class vMeleeAttackControlPDM : PlayablesStateBehaviour
{
// Anchor for the read-only exit time / end damage note; not real data.
[vMeleeAttackControlInfo]
[SerializeField] private int infoAnchor;
[Tooltip("normalizedTime of Active Damage")]
public float startDamage = 0.05f;
[Tooltip("normalizedTime of Disable Damage")]
public float endDamage = 0.9f;
public int damageMultiplier;
public int recoilID;
public int reactionID;
public vAttackType meleeAttackType = vAttackType.Unarmed;
[Tooltip("You can use a name as reference to trigger a custom HitDamageParticle")]
public string damageType;
// Drawn by the vBodyPartList anchor below: a PropertyAttribute on a collection field targets
// its elements, not the list, so the list UI has to hang off a scalar field instead.
[HideInInspector]
[Tooltip("This work with vMeleeManager to active vMeleeAttackObject from bodyPart and id")]
public List bodyParts = new List { "RightLowerArm" };
public bool ignoreDefense;
public bool activeRagdoll;
[vHideInInspector("activeRagdoll"), Tooltip("Time to keep Ragdoll active")]
public float senselessTime;
[Tooltip("Check true in the last attack of your combo to reset the triggers")]
public bool resetAttackTrigger;
public bool debug;
// Anchor the body part list UI hangs off; not real data.
[vBodyPartList]
[SerializeField] private int bodyPartsAnchor;
// Behaviour instances are cloned per PDM row at runtime, so per-play state is safe here.
[System.NonSerialized] private bool isActive;
[System.NonSerialized] private bool isAttacking;
[System.NonSerialized] private vIAttackListener mFighter;
[System.NonSerialized] private vMeleeManager meleeManager;
public override void OnStateEnter(in PlayablesStateContext context)
{
GameObject owner = ResolveOwner(context);
mFighter = owner != null ? owner.GetComponent() : null;
meleeManager = owner != null ? owner.GetComponent() : null;
isActive = false;
isAttacking = true;
if (mFighter != null)
mFighter.OnEnableAttack();
if (debug)
Debug.Log("Enter " + damageType);
}
public override void OnStateUpdate(in PlayablesStateContext context)
{
float normalizedTime = context.normalizedTime % 1f;
if (normalizedTime >= startDamage && normalizedTime <= endDamage && !isActive)
{
if (debug)
Debug.Log(context.RowName + " attack " + damageType + " enable damage in " +
System.Math.Round(normalizedTime, 2));
isActive = true;
ActiveDamage(true);
}
else if (normalizedTime > endDamage && isActive)
{
if (debug)
Debug.Log(context.RowName + " attack " + damageType + " disable damage in " +
System.Math.Round(normalizedTime, 2));
isActive = false;
ActiveDamage(false);
}
if (normalizedTime > endDamage && isAttacking)
{
isAttacking = false;
if (mFighter != null)
mFighter.OnDisableAttack();
}
}
public override void OnStateExit(in PlayablesStateContext context)
{
if (debug)
Debug.Log("Exit " + damageType);
if (isActive)
{
isActive = false;
ActiveDamage(false);
}
if (isAttacking)
{
isAttacking = false;
if (mFighter != null)
mFighter.OnDisableAttack();
}
if (mFighter != null && resetAttackTrigger)
mFighter.ResetAttackTriggers();
if (debug)
Debug.Log(context.RowName + " attack " + damageType + " stateExit");
}
private void ActiveDamage(bool value)
{
if (meleeManager)
{
meleeManager.SetActiveAttack(
bodyParts, meleeAttackType, value, damageMultiplier, recoilID, reactionID,
ignoreDefense, activeRagdoll, senselessTime, damageType);
}
}
private static GameObject ResolveOwner(in PlayablesStateContext context)
{
return context.Animator != null ? context.Animator.gameObject : null;
}
}
}
#endif