Files
utad-ui/Source/UTAD_UI/SkillTree/CharacterStatsComponent.cpp
2025-10-12 14:50:57 +02:00

192 lines
5.5 KiB
C++

#include "CharacterStatsComponent.h"
#include "SkillTreeComponent.h"
#include "GameFramework/Character.h"
#include "GameFramework/CharacterMovementComponent.h"
UCharacterStatsComponent::UCharacterStatsComponent()
{
PrimaryComponentTick.bCanEverTick = false;
// Default base stats
BaseMaxHealth = 100.0f;
BaseDamage = 10.0f;
BaseSpeed = 600.0f;
// Initialize current values
CurrentHealth = BaseMaxHealth;
MaxHealth = BaseMaxHealth;
CurrentDamage = BaseDamage;
CurrentSpeed = BaseSpeed;
// Initialize bonuses to 0
SkillHealthBonus = 0.0f;
SkillDamageBonus = 0.0f;
SkillSpeedBonus = 0.0f;
SkillHealthBonusPercent = 0.0f;
SkillDamageBonusPercent = 0.0f;
SkillSpeedBonusPercent = 0.0f;
}
void UCharacterStatsComponent::BeginPlay()
{
Super::BeginPlay();
// Find the skill tree component on the same actor
AActor* Owner = GetOwner();
if (Owner)
{
OwnerSkillTree = Owner->FindComponentByClass<USkillTreeComponent>();
// Bind to skill tree events
if (OwnerSkillTree)
{
OwnerSkillTree->OnSkillPurchased.AddDynamic(this, &UCharacterStatsComponent::OnSkillPurchased);
}
}
InitializeStats();
}
void UCharacterStatsComponent::InitializeStats()
{
MaxHealth = BaseMaxHealth;
CurrentHealth = MaxHealth;
CurrentDamage = BaseDamage;
CurrentSpeed = BaseSpeed;
RecalculateStats();
}
void UCharacterStatsComponent::OnSkillPurchased(FName SkillID)
{
// Called when a skill is purchased, update all stats
UpdateStatsFromSkillTree();
}
void UCharacterStatsComponent::UpdateStatsFromSkillTree()
{
if (!OwnerSkillTree)
{
return;
}
// Reset skill bonuses
SkillHealthBonus = 0.0f;
SkillDamageBonus = 0.0f;
SkillSpeedBonus = 0.0f;
SkillHealthBonusPercent = 0.0f;
SkillDamageBonusPercent = 0.0f;
SkillSpeedBonusPercent = 0.0f;
// Calculate total bonuses from purchased skills
TArray<FSkillNodeRuntime> AllSkills = OwnerSkillTree->GetAllSkillNodes();
for (const FSkillNodeRuntime& Skill : AllSkills)
{
if (Skill.CurrentState == ESkillNodeState::Purchased)
{
// Add flat bonuses
SkillHealthBonus += Skill.NodeData.HealthBonus;
SkillDamageBonus += Skill.NodeData.DamageBonus;
SkillSpeedBonus += Skill.NodeData.SpeedBonus;
// Add percentage bonuses
SkillHealthBonusPercent += Skill.NodeData.HealthBonusPercent;
SkillDamageBonusPercent += Skill.NodeData.DamageBonusPercent;
SkillSpeedBonusPercent += Skill.NodeData.SpeedBonusPercent;
}
}
RecalculateStats();
}
void UCharacterStatsComponent::RecalculateStats()
{
// Calculate final stats: Base + Flat Bonus + (Base * Percentage Bonus)
float OldMaxHealth = MaxHealth;
MaxHealth = BaseMaxHealth + SkillHealthBonus + (BaseMaxHealth * SkillHealthBonusPercent / 100.0f);
CurrentDamage = BaseDamage + SkillDamageBonus + (BaseDamage * SkillDamageBonusPercent / 100.0f);
CurrentSpeed = BaseSpeed + SkillSpeedBonus + (BaseSpeed * SkillSpeedBonusPercent / 100.0f);
// Scale current health proportionally if max health changed
if (OldMaxHealth > 0 && MaxHealth != OldMaxHealth)
{
float HealthPercent = CurrentHealth / OldMaxHealth;
CurrentHealth = MaxHealth * HealthPercent;
}
// Apply speed to character movement
ApplySpeedToMovement();
// Broadcast events
OnHealthChanged.Broadcast(CurrentHealth, MaxHealth);
OnDamageChanged.Broadcast(CurrentDamage);
OnSpeedChanged.Broadcast(CurrentSpeed);
OnStatsUpdated.Broadcast();
UE_LOG(LogTemp, Log, TEXT("Stats Updated - Health: %.0f/%.0f, Damage: %.0f, Speed: %.0f"),
CurrentHealth, MaxHealth, CurrentDamage, CurrentSpeed);
}
void UCharacterStatsComponent::TakeDamage(float DamageAmount)
{
if (DamageAmount <= 0.0f)
{
return;
}
CurrentHealth = FMath::Clamp(CurrentHealth - DamageAmount, 0.0f, MaxHealth);
OnHealthChanged.Broadcast(CurrentHealth, MaxHealth);
if (CurrentHealth <= 0.0f)
{
UE_LOG(LogTemp, Warning, TEXT("Character has died!"));
}
}
void UCharacterStatsComponent::Heal(float HealAmount)
{
if (HealAmount <= 0.0f)
{
return;
}
CurrentHealth = FMath::Clamp(CurrentHealth + HealAmount, 0.0f, MaxHealth);
OnHealthChanged.Broadcast(CurrentHealth, MaxHealth);
}
void UCharacterStatsComponent::SetHealth(float NewHealth)
{
CurrentHealth = FMath::Clamp(NewHealth, 0.0f, MaxHealth);
OnHealthChanged.Broadcast(CurrentHealth, MaxHealth);
}
FText UCharacterStatsComponent::GetHealthText() const
{
return FText::Format(FText::FromString(TEXT("{0} / {1}")),
FText::AsNumber(FMath::RoundToInt(CurrentHealth)),
FText::AsNumber(FMath::RoundToInt(MaxHealth)));
}
FText UCharacterStatsComponent::GetDamageText() const
{
return FText::Format(FText::FromString(TEXT("{0}")),
FText::AsNumber(FMath::RoundToInt(CurrentDamage)));
}
FText UCharacterStatsComponent::GetSpeedText() const
{
return FText::Format(FText::FromString(TEXT("{0}")),
FText::AsNumber(FMath::RoundToInt(CurrentSpeed)));
}
void UCharacterStatsComponent::ApplySpeedToMovement()
{
// Apply speed to character movement component
ACharacter* CharacterOwner = Cast<ACharacter>(GetOwner());
if (CharacterOwner && CharacterOwner->GetCharacterMovement())
{
CharacterOwner->GetCharacterMovement()->MaxWalkSpeed = CurrentSpeed;
UE_LOG(LogTemp, Log, TEXT("Applied movement speed: %.0f"), CurrentSpeed);
}
}