192 lines
5.5 KiB
C++
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);
|
|
}
|
|
} |