187 lines
5.7 KiB
C#
187 lines
5.7 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.Events;
|
||
|
|
|
||
|
|
public class CharacterStats : MonoBehaviour
|
||
|
|
{
|
||
|
|
[Header("Identity & Level")]
|
||
|
|
[SerializeField] private string characterName = "Character";
|
||
|
|
[SerializeField] private int level = 1;
|
||
|
|
|
||
|
|
[Header("Health Stats")]
|
||
|
|
[SerializeField] private float maxHealth = 100f;
|
||
|
|
[SerializeField] private float currentHealth;
|
||
|
|
[SerializeField] private float healthRegenRate = 0.5f; // per second
|
||
|
|
|
||
|
|
[Header("Mana Stats")]
|
||
|
|
[SerializeField] private float maxMana = 50f;
|
||
|
|
[SerializeField] private float currentMana;
|
||
|
|
[SerializeField] private float manaRegenRate = 1.0f; // per second
|
||
|
|
|
||
|
|
[Header("Stamina Stats")]
|
||
|
|
[SerializeField] private float maxStamina = 100f;
|
||
|
|
[SerializeField] private float currentStamina;
|
||
|
|
[SerializeField] private float staminaRegenRate = 5.0f; // per second
|
||
|
|
|
||
|
|
[Header("Combat Attributes")]
|
||
|
|
[SerializeField] private float baseDamage = 10f;
|
||
|
|
[SerializeField] private float attackSpeed = 1.0f; // Attacks per second
|
||
|
|
[SerializeField] private float attackRange = 2.0f;
|
||
|
|
[SerializeField] private float armor = 0f;
|
||
|
|
[SerializeField] private float moveSpeedMultiplier = 1.0f;
|
||
|
|
|
||
|
|
[Header("Equipment")]
|
||
|
|
[SerializeField] private string currentWeapon = "Unarmed";
|
||
|
|
[SerializeField] private GameObject weaponPrefab;
|
||
|
|
|
||
|
|
[Header("Rewards & Drops (For NPCs / Enemies)")]
|
||
|
|
[SerializeField] private int expReward = 50;
|
||
|
|
[SerializeField] private int goldReward = 25;
|
||
|
|
[SerializeField] private List<GameObject> dropReward = new List<GameObject>();
|
||
|
|
|
||
|
|
[Header("Events")]
|
||
|
|
public UnityEvent<float, float> onHealthChanged; // current, max
|
||
|
|
public UnityEvent<float, float> onManaChanged; // current, max
|
||
|
|
public UnityEvent<float, float> onStaminaChanged; // current, max
|
||
|
|
public UnityEvent<GameObject> onDeath; // killer
|
||
|
|
|
||
|
|
public bool IsDead { get; private set; } = false;
|
||
|
|
|
||
|
|
private void Awake()
|
||
|
|
{
|
||
|
|
currentHealth = maxHealth;
|
||
|
|
currentMana = maxMana;
|
||
|
|
currentStamina = maxStamina;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void Update()
|
||
|
|
{
|
||
|
|
if (IsDead) return;
|
||
|
|
|
||
|
|
// Passive Regeneration
|
||
|
|
RegenerateStats();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void RegenerateStats()
|
||
|
|
{
|
||
|
|
if (currentHealth < maxHealth && healthRegenRate > 0)
|
||
|
|
{
|
||
|
|
Heal(healthRegenRate * Time.deltaTime);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (currentMana < maxMana && manaRegenRate > 0)
|
||
|
|
{
|
||
|
|
RestoreMana(manaRegenRate * Time.deltaTime);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (currentStamina < maxStamina && staminaRegenRate > 0)
|
||
|
|
{
|
||
|
|
RestoreStamina(staminaRegenRate * Time.deltaTime);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- Damage & Healing Methods ---
|
||
|
|
public void TakeDamage(float damageAmount, GameObject attacker = null)
|
||
|
|
{
|
||
|
|
if (IsDead) return;
|
||
|
|
|
||
|
|
// Apply Armor reduction
|
||
|
|
float netDamage = Mathf.Max(damageAmount - armor, 1.0f);
|
||
|
|
currentHealth -= netDamage;
|
||
|
|
currentHealth = Mathf.Clamp(currentHealth, 0, maxHealth);
|
||
|
|
|
||
|
|
onHealthChanged?.Invoke(currentHealth, maxHealth);
|
||
|
|
Debug.Log($"[{gameObject.name}] Took {netDamage} damage from {(attacker != null ? attacker.name : "Unknown")}. HP: {currentHealth}/{maxHealth}");
|
||
|
|
|
||
|
|
if (currentHealth <= 0)
|
||
|
|
{
|
||
|
|
Die(attacker);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Heal(float amount)
|
||
|
|
{
|
||
|
|
if (IsDead) return;
|
||
|
|
|
||
|
|
currentHealth += amount;
|
||
|
|
currentHealth = Mathf.Clamp(currentHealth, 0, maxHealth);
|
||
|
|
onHealthChanged?.Invoke(currentHealth, maxHealth);
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- Mana Methods ---
|
||
|
|
public bool UseMana(float amount)
|
||
|
|
{
|
||
|
|
if (currentMana >= amount)
|
||
|
|
{
|
||
|
|
currentMana -= amount;
|
||
|
|
onManaChanged?.Invoke(currentMana, maxMana);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void RestoreMana(float amount)
|
||
|
|
{
|
||
|
|
currentMana = Mathf.Clamp(currentMana + amount, 0, maxMana);
|
||
|
|
onManaChanged?.Invoke(currentMana, maxMana);
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- Stamina Methods ---
|
||
|
|
public bool UseStamina(float amount)
|
||
|
|
{
|
||
|
|
if (currentStamina >= amount)
|
||
|
|
{
|
||
|
|
currentStamina -= amount;
|
||
|
|
onStaminaChanged?.Invoke(currentStamina, maxStamina);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void RestoreStamina(float amount)
|
||
|
|
{
|
||
|
|
currentStamina = Mathf.Clamp(currentStamina + amount, 0, maxStamina);
|
||
|
|
onStaminaChanged?.Invoke(currentStamina, maxStamina);
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- Death Handling ---
|
||
|
|
private void Die(GameObject killer)
|
||
|
|
{
|
||
|
|
IsDead = true;
|
||
|
|
Debug.Log($"<color=red>[{gameObject.name}] has been defeated!</color>");
|
||
|
|
|
||
|
|
onDeath?.Invoke(killer);
|
||
|
|
|
||
|
|
// Spawn Loot Drops if assigned
|
||
|
|
SpawnLoot();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void SpawnLoot()
|
||
|
|
{
|
||
|
|
if (dropReward == null || dropReward.Count == 0) return;
|
||
|
|
|
||
|
|
foreach (GameObject lootPrefab in dropReward)
|
||
|
|
{
|
||
|
|
if (lootPrefab != null)
|
||
|
|
{
|
||
|
|
Vector3 spawnOffset = new Vector3(UnityEngine.Random.Range(-0.5f, 0.5f), 0.2f, UnityEngine.Random.Range(-0.5f, 0.5f));
|
||
|
|
Instantiate(lootPrefab, transform.position + spawnOffset, Quaternion.identity);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- Getters & Setters ---
|
||
|
|
public string CharacterName => characterName;
|
||
|
|
public int Level => level;
|
||
|
|
public float HealthPercentage => currentHealth / maxHealth;
|
||
|
|
public float ManaPercentage => currentMana / maxMana;
|
||
|
|
public float StaminaPercentage => currentStamina / maxStamina;
|
||
|
|
public float AttackSpeed => attackSpeed;
|
||
|
|
public float AttackRange => attackRange;
|
||
|
|
public float BaseDamage => baseDamage;
|
||
|
|
public string CurrentWeapon => currentWeapon;
|
||
|
|
public int ExpReward => expReward;
|
||
|
|
public int GoldReward => goldReward;
|
||
|
|
}
|