229 lines
8.1 KiB
C#
229 lines
8.1 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Invector;
|
|
using Invector.vCharacterController;
|
|
using Invector.vEventSystems;
|
|
using UnityEngine;
|
|
|
|
namespace Beyond
|
|
{
|
|
public class bThirdPersonController : vThirdPersonController
|
|
{
|
|
protected bool m_isDashing;
|
|
protected bool m_GodMode = false;
|
|
public bool m_ignoreTriggers = true;
|
|
|
|
[Header("Beyond Health Logic")]
|
|
public float healthRecoveryCap = 1f;
|
|
|
|
[Header("Beyond's Custom Settings")]
|
|
public bool useAnimationBasedRotation = false;
|
|
|
|
[Header("Beyond's Dash Settings")]
|
|
public string dashBlendTreeState = "Dash_Directional";
|
|
|
|
// Internal flag to lock animator parameters during dash
|
|
private bool _lockAnimParamsForDash = false;
|
|
|
|
public bool GodMode
|
|
{
|
|
get => m_GodMode;
|
|
set
|
|
{
|
|
m_GodMode = value;
|
|
isImmortal = m_GodMode;
|
|
}
|
|
}
|
|
|
|
protected override bool canRecoverHealth
|
|
{
|
|
get
|
|
{
|
|
float limitHP = maxHealth * healthRecoveryCap;
|
|
return base.canRecoverHealth && (_currentHealth < limitHP);
|
|
}
|
|
}
|
|
|
|
public bool IsDashingOrRolling()
|
|
{
|
|
return m_isDashing || isRolling;
|
|
}
|
|
|
|
protected override void Start()
|
|
{
|
|
base.Start();
|
|
}
|
|
|
|
protected override void RollBehavior()
|
|
{
|
|
base.RollBehavior();
|
|
}
|
|
|
|
public override void Roll()
|
|
{
|
|
Dash();
|
|
}
|
|
|
|
public virtual void Dash()
|
|
{
|
|
OnRoll.Invoke();
|
|
isRolling = true;
|
|
ReduceStamina(rollStamina, false);
|
|
currentStaminaRecoveryDelay = 2f;
|
|
|
|
// 1. Handle Stationary (Backwards Dash)
|
|
if (input.sqrMagnitude < 0.05f)
|
|
{
|
|
ApplyDashParams(0f, -1f);
|
|
}
|
|
else
|
|
{
|
|
// 2. Handle Directional Input (Camera Relative -> Character Relative)
|
|
|
|
// A. Get the Input Direction relative to the Camera
|
|
Vector3 inputDir = Vector3.zero;
|
|
if (Camera.main != null)
|
|
{
|
|
// Convert joystick input (X,Y) into World Space based on Camera facing
|
|
Vector3 camFwd = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;
|
|
Vector3 camRight = Vector3.Scale(Camera.main.transform.right, new Vector3(1, 0, 1)).normalized;
|
|
inputDir = (camFwd * input.y + camRight * input.x).normalized;
|
|
}
|
|
else
|
|
{
|
|
// Fallback if no camera found
|
|
inputDir = new Vector3(input.x, 0, input.y).normalized;
|
|
}
|
|
|
|
// B. Convert that World Direction into the Character's Local Space
|
|
// This tells us: "Is the input to the Left, Right, or Forward of ME?"
|
|
Vector3 localDir = transform.InverseTransformDirection(inputDir);
|
|
|
|
// C. Send to Animator
|
|
ApplyDashParams(localDir.x, localDir.z);
|
|
}
|
|
|
|
// 3. Play Animation
|
|
animator.CrossFadeInFixedTime(dashBlendTreeState, rollTransition, baseLayer);
|
|
|
|
// 4. Lock parameters briefly so Invector doesn't overwrite them immediately
|
|
StartCoroutine(LockDashParamsRoutine());
|
|
}
|
|
|
|
// Helper to set params and lock the update loop
|
|
private void ApplyDashParams(float x, float y)
|
|
{
|
|
_lockAnimParamsForDash = true;
|
|
animator.SetFloat(vAnimatorParameters.InputHorizontal, x);
|
|
animator.SetFloat(vAnimatorParameters.InputVertical, y);
|
|
}
|
|
|
|
// Release the lock after a short delay (once the blend has firmly started)
|
|
private IEnumerator LockDashParamsRoutine()
|
|
{
|
|
yield return new WaitForSeconds(0.2f); // Adjust this if the blend pops back too soon
|
|
_lockAnimParamsForDash = false;
|
|
}
|
|
|
|
// --- CRITICAL FIX: Override Invector's Parameter Update ---
|
|
public override void UpdateAnimatorParameters()
|
|
{
|
|
// If we are locking parameters for the dash, DO NOT let the base class overwrite them.
|
|
if (_lockAnimParamsForDash) return;
|
|
|
|
// Otherwise, run standard Invector logic
|
|
base.UpdateAnimatorParameters();
|
|
}
|
|
|
|
// Standard overrides below...
|
|
public void OnEvadeStart() { if (!m_GodMode) isImmortal = true; }
|
|
public void OnEvadeEnd() { if (!m_GodMode) isImmortal = false; }
|
|
public override void ActionsControl() { base.ActionsControl(); m_isDashing = IsAnimatorTag("IsDashing"); }
|
|
|
|
protected override void DeadAnimation()
|
|
{
|
|
if (!isDead) return;
|
|
if (!triggerDieBehaviour) { triggerDieBehaviour = true; DeathBehaviour(); }
|
|
if (deathBy == DeathBy.Animation)
|
|
{
|
|
int deadLayer = 0;
|
|
var info = animatorStateInfos.GetStateInfoUsingTag("Dead");
|
|
if (info != null)
|
|
{
|
|
if (!animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.99f && groundDistance <= 0.15f) RemoveComponents();
|
|
}
|
|
}
|
|
else if (deathBy == DeathBy.AnimationWithRagdoll)
|
|
{
|
|
int deadLayer = 0;
|
|
var info = animatorStateInfos.GetStateInfoUsingTag("Dead");
|
|
if (info != null)
|
|
{
|
|
if (!animator.IsInTransition(deadLayer) && info.normalizedTime >= 0.8f) onActiveRagdoll.Invoke(null);
|
|
}
|
|
}
|
|
else if (deathBy == DeathBy.Ragdoll)
|
|
{
|
|
onActiveRagdoll.Invoke(null);
|
|
}
|
|
}
|
|
|
|
public void RemoveAnimatorTags()
|
|
{
|
|
animatorStateInfos.stateInfos.vToList().ForEach(infos => infos.tags.Clear());
|
|
}
|
|
|
|
public override void ControlAnimatorRootMotion()
|
|
{
|
|
if (!this.enabled) return;
|
|
if (isRolling) { RollBehavior(); return; }
|
|
if (customAction || lockAnimMovement)
|
|
{
|
|
StopCharacterWithLerp();
|
|
transform.position = animator.rootPosition;
|
|
transform.rotation = animator.rootRotation;
|
|
}
|
|
else if (IsAnimatorTag("Attack"))
|
|
{
|
|
if (lockRotation) StopCharacterWithLerp();
|
|
transform.position = animator.rootPosition;
|
|
}
|
|
if (useRootMotion) MoveCharacter(moveDirection);
|
|
}
|
|
|
|
protected override void OnTriggerEnter(Collider other)
|
|
{
|
|
if (!m_ignoreTriggers) onActionEnter.Invoke(other);
|
|
}
|
|
|
|
protected override void OnTriggerStay(Collider other)
|
|
{
|
|
try { CheckForAutoCrouch(other); }
|
|
catch (UnityException e) { Debug.LogWarning(e.Message); }
|
|
if (!m_ignoreTriggers) base.OnTriggerStay(other);
|
|
}
|
|
|
|
protected override void OnTriggerExit(Collider other)
|
|
{
|
|
AutoCrouchExit(other);
|
|
if (!m_ignoreTriggers) base.OnTriggerExit(other);
|
|
}
|
|
|
|
void DrawWeaponLowLeft() { }
|
|
|
|
public override void ControlRotationType()
|
|
{
|
|
if (lockAnimRotation || lockRotation || customAction || isRolling) return;
|
|
bool validInput = input != Vector3.zero || (isStrafing ? strafeSpeed.rotateWithCamera : freeSpeed.rotateWithCamera);
|
|
if (validInput)
|
|
{
|
|
if (lockAnimMovement)
|
|
{
|
|
inputSmooth = Vector3.Lerp(inputSmooth, input, (isStrafing ? strafeSpeed.movementSmooth : freeSpeed.movementSmooth) * Time.deltaTime);
|
|
}
|
|
Vector3 dir = (isStrafing && isGrounded && (!isSprinting || sprintOnlyFree == false) || (freeSpeed.rotateWithCamera && input == Vector3.zero)) && rotateTarget ? rotateTarget.forward : moveDirection;
|
|
if (isStrafing || !useAnimationBasedRotation) RotateToDirection(dir);
|
|
}
|
|
}
|
|
}
|
|
} |