115 lines
3.9 KiB
C#
115 lines
3.9 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using UnityEngine;
|
||
|
|
using WarGame.Data;
|
||
|
|
|
||
|
|
namespace WarGame.Units
|
||
|
|
{
|
||
|
|
[System.Serializable]
|
||
|
|
public class UnitProgression
|
||
|
|
{
|
||
|
|
[SerializeField] private UnitDataSO unitData;
|
||
|
|
[SerializeField] private int currentLevel = 1;
|
||
|
|
[SerializeField] private int currentExp = 0;
|
||
|
|
[SerializeField] private int totalKills = 0;
|
||
|
|
[SerializeField] private int battlesSurvived = 0;
|
||
|
|
|
||
|
|
public UnitDataSO UnitData => unitData;
|
||
|
|
public int CurrentLevel => currentLevel;
|
||
|
|
public int CurrentExp => currentExp;
|
||
|
|
public int TotalKills => totalKills;
|
||
|
|
public int BattlesSurvived => battlesSurvived;
|
||
|
|
|
||
|
|
public event Action<int, int> OnExpGained; // gainedAmount, currentTotal
|
||
|
|
public event Action<int> OnLevelUp; // newLevel
|
||
|
|
public event Action<UnlockedTactic> OnTacticUnlocked;
|
||
|
|
|
||
|
|
public UnitProgression(UnitDataSO data, int startingLevel = 1)
|
||
|
|
{
|
||
|
|
unitData = data;
|
||
|
|
currentLevel = Mathf.Clamp(startingLevel, 1, data != null ? data.maxLevel : 10);
|
||
|
|
currentExp = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
public int ExpNeededForNextLevel => unitData != null ? unitData.GetExpRequiredForLevel(currentLevel) : 100;
|
||
|
|
public float ExpPercent => unitData != null ? (float)currentExp / ExpNeededForNextLevel : 0f;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Adds experience to this unit, handling level-ups and tactic unlocks.
|
||
|
|
/// </summary>
|
||
|
|
public void AddExperience(int amount)
|
||
|
|
{
|
||
|
|
if (unitData == null || currentLevel >= unitData.maxLevel || amount <= 0) return;
|
||
|
|
|
||
|
|
currentExp += amount;
|
||
|
|
OnExpGained?.Invoke(amount, currentExp);
|
||
|
|
|
||
|
|
while (currentLevel < unitData.maxLevel && currentExp >= ExpNeededForNextLevel)
|
||
|
|
{
|
||
|
|
currentExp -= ExpNeededForNextLevel;
|
||
|
|
currentLevel++;
|
||
|
|
OnLevelUp?.Invoke(currentLevel);
|
||
|
|
|
||
|
|
// Notify of any new tactics unlocked at this level
|
||
|
|
List<UnlockedTactic> tactics = unitData.unlockedTactics;
|
||
|
|
for (int i = 0; i < tactics.Count; i++)
|
||
|
|
{
|
||
|
|
if (tactics[i].requiredLevel == currentLevel)
|
||
|
|
{
|
||
|
|
OnTacticUnlocked?.Invoke(tactics[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public void RecordKill()
|
||
|
|
{
|
||
|
|
totalKills++;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void RecordBattleSurvived()
|
||
|
|
{
|
||
|
|
battlesSurvived++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Calculated runtime stats
|
||
|
|
public float GetMaxHealth()
|
||
|
|
{
|
||
|
|
if (unitData == null) return 100f;
|
||
|
|
return unitData.maxHealth + (currentLevel - 1) * unitData.healthGrowth;
|
||
|
|
}
|
||
|
|
|
||
|
|
public float GetAttackDamage()
|
||
|
|
{
|
||
|
|
if (unitData == null) return 10f;
|
||
|
|
return unitData.attackDamage + (currentLevel - 1) * unitData.damageGrowth;
|
||
|
|
}
|
||
|
|
|
||
|
|
public float GetDefenseArmor()
|
||
|
|
{
|
||
|
|
if (unitData == null) return 0f;
|
||
|
|
return unitData.defenseArmor + (currentLevel - 1) * unitData.defenseGrowth;
|
||
|
|
}
|
||
|
|
|
||
|
|
public float GetMoveSpeed()
|
||
|
|
{
|
||
|
|
if (unitData == null) return 3.5f;
|
||
|
|
return unitData.moveSpeed + (currentLevel - 1) * unitData.speedGrowth;
|
||
|
|
}
|
||
|
|
|
||
|
|
public float GetAttackRange() => unitData != null ? unitData.attackRange : 1.5f;
|
||
|
|
public float GetAttackInterval() => unitData != null ? unitData.attackInterval : 1.2f;
|
||
|
|
public float GetCriticalChance() => unitData != null ? unitData.criticalChance : 0.05f;
|
||
|
|
|
||
|
|
public bool HasTactic(UnitTacticType tactic, out UnlockedTactic config)
|
||
|
|
{
|
||
|
|
if (unitData == null)
|
||
|
|
{
|
||
|
|
config = null;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return unitData.HasTacticUnlocked(tactic, currentLevel, out config);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|