RiftMayhem/Assets/Scripts/Player/AbilityKeyBinder.cs

295 lines
9.6 KiB
C#

using Kryz.CharacterStats.Examples;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AbilityKeyBinder : MonoBehaviour
{
[Header("Listeners:")]
[SerializeField] private GameEventListener onLocalPlayerFainted;
[SerializeField] private GameEventListener onLocalPlayerPermaDeath;
[SerializeField] private GameEventListener onLocalPlayerRevived;
[Space]
[SerializeField] private BaseAbility ability;
[SerializeField] private GameKey key;
[SerializeField] private CastingStateController castingStateController;
[SerializeField] private GameEvent_AbilityKeyBinder onAbilityKeyBinderSpawned;
[SerializeField] private GameInputBinding gamepadBinding; // New field for gamepad binding
private Taggable userTag;
private Mana mana;
private Health health;
public Health Health => health;
public Mana Mana => mana;
public BaseAbility Ability => ability;
public GameKey GameKey => key;
Coroutine currentChanneling;
NetworkedChanneling networkedChanneling;
AbilityBindInstance abilityBindInstance;
AbilityCooldownTracker cooldownTracker;
bool isDead = false;
bool abilitySlotUnlocked = false;
bool isComboAbility = false;
ComboAbility combo;
ComboState comboState = new ComboState();
float finalHealthCost;
float finalManaCost;
RuntimeAbilityInstance abilityInstance;
public RuntimeAbilityInstance AbilityInstance => abilityInstance;
private void Awake()
{
userTag = GetComponentInParent<Taggable>();
mana = GetComponentInParent<Mana>();
health = GetComponentInParent<Health>();
cooldownTracker = userTag.GetComponentInChildren<AbilityCooldownTracker>();
}
private void Start()
{
onLocalPlayerFainted.Response.AddListener(() =>
{
isDead = true;
});
onLocalPlayerPermaDeath.Response.AddListener(() =>
{
isDead = true;
});
onLocalPlayerRevived.Response.AddListener(() =>
{
isDead = false;
});
onAbilityKeyBinderSpawned.Raise(this);
}
bool isInputPressed;
bool isInputReleased;
void Update()
{
if (isDead) return;
if (!abilitySlotUnlocked && ability.animationType != AbilityAnimationType.Potion) return;
// Check for input using both keyboard and gamepad
isInputPressed =
(key != null && Input.GetKeyDown(key.keyCode)) ||
(!string.IsNullOrEmpty(gamepadBinding.bindingName) && GameInputManager.Instance.GetButtonDown(gamepadBinding.bindingName));
isInputReleased =
(key != null && Input.GetKeyUp(key.keyCode)) ||
(!string.IsNullOrEmpty(gamepadBinding.bindingName) && GameInputManager.Instance.GetButtonUp(gamepadBinding.bindingName));
if (isInputPressed)
{
if (abilityBindInstance != null)
abilityBindInstance.pressed.SetActive(true);
if(abilityInstance != null)
{
if(abilityInstance.CanExecute(userTag))
{
castingStateController.RequestAbilityCast(abilityInstance, () =>
{
abilityInstance.Execute(userTag);
});
}
}
else
if (IsAbilityOffCooldown() && mana.EnoughMana(ability.GetFinalManaCost(mana)) && health.EnoughHealth(ability.GetFinalHealthCost(health)))
{
if (ability is ChanneledAbility)
{
castingStateController.RequestAbilityChannel(ability, () =>
{
networkedChanneling = ((ChanneledAbility)ability).ExecuteChannel(userTag, ref currentChanneling);
if (ability.cooldown > 0)
{
cooldownTracker.StartAbilityCooldown(ability);
abilityBindInstance.StartCooldownTrackerUI();
}
});
}
else if (isComboAbility)
{
if (mana.EnoughMana(GetCurrentAbility().GetFinalManaCost(mana)) && health.EnoughHealth(GetCurrentAbility().GetFinalHealthCost(health)))
{
castingStateController.RequestAbilityCast(GetCurrentAbility(), () =>
{
GetCurrentAbility().Execute(userTag);
AdvanceCombo();
});
}
else
{
ResetCombo();
}
}
else
{
castingStateController.RequestAbilityCast(ability, () =>
{
ability.Execute(userTag);
if (ability.cooldown > 0)
{
cooldownTracker.StartAbilityCooldown(ability);
abilityBindInstance.StartCooldownTrackerUI();
}
});
}
}
}
if (isInputReleased)
{
if (abilityBindInstance != null)
abilityBindInstance.pressed.SetActive(false);
if (currentChanneling != null)
{
if (networkedChanneling != null)
{
networkedChanneling.StopCoroutine(currentChanneling);
}
else
{
StopCoroutine(currentChanneling);
}
castingStateController.ResetChannelingCast();
CastBarHandler.Instance.CancelChannelingOnButtonReleased();
}
if (networkedChanneling != null)
{
networkedChanneling.channeling = false;
networkedChanneling.DisableVisuals();
}
}
}
public void SetupAbilityBindInstance(AbilityBindInstance abilityBindInstance)
{
Debug.Log("#RACE: SETUP BIND INSTANCE");
this.abilityBindInstance = abilityBindInstance;
mana.onResourceChanged.AddListener(OnManaChanged);
health.onResourceChanged.AddListener(OnHealthChanged);
if (isComboAbility)
abilityBindInstance.ForceUpdateOnComboAbility(GetCurrentAbility());
}
[ContextMenu("debug Add manacost reduction")]
public void AddManaCostModifierDebug()
{
abilityInstance.AddModifier(AbilityModifier.CreateManaCostReduction(100f));
}
public void OnManaChanged(float currentMana)
{
if (ability == null || abilityInstance == null) return;
if (isComboAbility)
{
finalManaCost = GetCurrentAbility().GetFinalManaCost(mana);
}
else
{
finalManaCost = abilityInstance.GetFinalManaCost(CostCalculationContext.FromUser(userTag));
}
abilityBindInstance.manaCost.text = finalManaCost.ToString("F0");
abilityBindInstance.noMana.SetActive(!mana.EnoughMana(finalManaCost));
}
public void OnHealthChanged(float currentHealth)
{
if (ability == null || abilityInstance == null) return;
if (isComboAbility)
{
finalHealthCost = GetCurrentAbility().GetFinalHealthCost(health);
}
else
{
finalHealthCost = abilityInstance.GetFinalHealthCost(CostCalculationContext.FromUser(userTag));
}
abilityBindInstance.healthCost.text = finalHealthCost.ToString("F0");
abilityBindInstance.healthCostGO.SetActive(finalHealthCost > 0);
abilityBindInstance.noHealth.SetActive(!health.EnoughHealth(finalHealthCost));
}
public bool IsAbilityOffCooldown()
{
if (abilityBindInstance != null)
return !abilityInstance.IsOnCooldown;
return ability.cooldown <= 0 || !cooldownTracker.OnCooldown(ability);
}
public void BindAbility(BaseAbility ability)
{
Debug.Log("#RACE: BIND ABILITY");
this.ability = ability;
if (ability is ComboAbility comboAbility)
{
isComboAbility = true;
combo = comboAbility;
abilityBindInstance.ForceUpdateOnComboAbility(GetCurrentAbility());
}
else
{
abilityInstance = new RuntimeAbilityInstance(ability);
isComboAbility = false;
combo = null;
}
onAbilityKeyBinderSpawned.Raise(this);
}
public void SetUnlockAbilitySlot(bool unlocked)
{
abilitySlotUnlocked = unlocked;
abilityBindInstance.SetUnlocked(unlocked);
}
private void AdvanceCombo()
{
comboState.currentComboIndex++;
comboState.currentComboIndex %= combo.comboChain.Count;
abilityBindInstance.ForceUpdateOnComboAbility(GetCurrentAbility());
}
private void ResetCombo()
{
comboState.currentComboIndex = 0;
abilityBindInstance.ForceUpdateOnComboAbility(GetCurrentAbility());
}
// Public methods for external access (useful for UI or debugging)
public int GetCurrentComboIndex()
{
return comboState.currentComboIndex;
}
public BaseAbility GetCurrentAbility()
{
if (combo.comboChain.Count == 0) return null;
int index = GetCurrentComboIndex();
return combo.comboChain[index];
}
public int GetComboLength()
{
return combo.comboChain.Count;
}
public List<BaseAbility> GetComboChain()
{
return new List<BaseAbility>(combo.comboChain); // Return copy to prevent external modification
}
}