0. 개요

크리티컬 확률, 크리티컬 데미지, 크리티컬 저항을 이용하여 데미지에 크리티컬 계산을 도입한다.

 

 

1. 크리티컬 계산

(1) 캡쳐할 속성 선언

// 단일 인스턴스 - 정적 구조체
struct AuraDamageStatics
{
	// 속성에 대한 Def 생성
	DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);
	DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetration);
	DECLARE_ATTRIBUTE_CAPTUREDEF(BlockChance);
	DECLARE_ATTRIBUTE_CAPTUREDEF(CriticalHitChance)
	DECLARE_ATTRIBUTE_CAPTUREDEF(CriticalHitDamage)
	DECLARE_ATTRIBUTE_CAPTUREDEF(CriticalHitResistance)

실행 계산에서 사용할(캡쳐할) 속성을 선언한다.

 

 

(2) 캡쳐할 속성 초기화

struct AuraDamageStatics
{
	// 속성에 대한 Def 생성
	DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);
	DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetration);
	DECLARE_ATTRIBUTE_CAPTUREDEF(BlockChance);
	DECLARE_ATTRIBUTE_CAPTUREDEF(CriticalHitChance)
	DECLARE_ATTRIBUTE_CAPTUREDEF(CriticalHitDamage)
	DECLARE_ATTRIBUTE_CAPTUREDEF(CriticalHitResistance)
	
	AuraDamageStatics()
	{
		// 정적 클래스, 속성, 소스 or 타겟, 스냅샷 여부
		DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, Armor, Target, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, ArmorPenetration, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, BlockChance, Target, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, CriticalHitChance, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, CriticalHitDamage, Source, false);
		DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, CriticalHitResistance, Target, false);
	}
};

캡쳐할 속성을 선언한 이후에 속성 세트를 참고하여 캡쳐할 속성을 초기화한다.

 

 

(3) 속성 매핑

UExecCalc_Damage::UExecCalc_Damage()
{
	RelevantAttributesToCapture.Add(DamageStatics().ArmorDef);
	RelevantAttributesToCapture.Add(DamageStatics().ArmorPenetrationDef);
	RelevantAttributesToCapture.Add(DamageStatics().BlockChanceDef);
	RelevantAttributesToCapture.Add(DamageStatics().CriticalHitChanceDef);
	RelevantAttributesToCapture.Add(DamageStatics().CriticalHitDamageDef);
	RelevantAttributesToCapture.Add(DamageStatics().CriticalHitResistanceDef);
}

생성자를 통해 캡쳐할 속성을 매핑한다.

 

 

(4) 계산

	// 방어 데미지 계산
	Damage *= (100 - EffectiveArmor * EffectiveArmorCoefficient) / 100.f;

	// 크리티컬 확률, 크리티컬 데미지, 타겟 크리 저항
	float SourceCriticalHitChance = 0.f;
	float SourceCriticalHitDamage = 0.f;
	float TargetCriticalHitResistance = 0.f;
	ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().CriticalHitChanceDef, EvalParams, SourceCriticalHitChance);
	ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().CriticalHitDamageDef, EvalParams, SourceCriticalHitDamage);
	ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().CriticalHitResistanceDef, EvalParams, TargetCriticalHitResistance);

	SourceCriticalHitChance = FMath::Max<float>(SourceCriticalHitChance, 0.f);
	SourceCriticalHitDamage = FMath::Max<float>(SourceCriticalHitDamage, 0.f);
	TargetCriticalHitResistance = FMath::Max<float>(TargetCriticalHitResistance, 0.f);

	// 커브 테이블 - 크리티컬 저항 계수 가져오기
	FRealCurve* CriticalHitResistanceCurve = CharacterClassInfo->DamageCalculationCoefficients->FindCurve(FName("CriticalHitResistance"), FString());
	const float CriticalHitResistanceCoefficient = CriticalHitResistanceCurve->Eval(SourceCombatInterface->GetPlayerLevel());

	// 최종 크리티컬
	float FinalCriticalHitChance = SourceCriticalHitChance - (TargetCriticalHitResistance * CriticalHitResistanceCoefficient);

	const bool bCriticalHit = FMath::RandRange(1, 100) < FinalCriticalHitChance;

	// 크리티컬 발생 데미지
	if (bCriticalHit)
	{
		Damage = (Damage * 2.f) + SourceCriticalHitDamage;
	}

	// 속성, 수정자, 속성 값
	const FGameplayModifierEvaluatedData EvalData(UAuraAttributeSet::GetIncomingDamageAttribute(), EGameplayModOp::Additive, Damage);
	OutexecutionOutput.AddOutputModifier(EvalData);
}

소스의 크리티컬 확률, 크리티컬 데미지를 가져오고 타겟의 크리티컬 저항을 가져온다.

데미지 계수 커브 테이블에서 크리티컬 저항 계수를 가져온다.

가져온 값을 이용하여 확률을 계산하고 데미지에 반영한다.