Files
beyond/Assets/Scripts/InvectorDerivatives/bThirdPersonController.cs

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);
}
}
}
}