Files
DS-Combat_analy/DS-기획_메뉴얼-전투_로직.md
2025-10-27 17:04:37 +09:00

2105 lines
68 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 기획 메뉴얼 - 전투 로직
## 1. 데미지 계산
### 1.1 BaseDamage 계산 과정
> **코드 위치**:
> - `CharacterStatDataRow.h:104-107` - 기본 값 정의
> - `WSCharacterPlayer.cpp:3214-3245` - 1차 스탯 반영
> - `WSCharacterPlayer.cpp:3805-3806` - 장비 효과
> - `WSCharacterPlayer.cpp:4022` - 패시브 스탯 적용
> - `WSDamageCalculation.cpp:316-322, 543-613` - 최종 BaseDamage 결정
BaseDamage는 여러 단계를 거쳐 계산됩니다:
#### 1단계: 캐릭터 기본 값 (CharacterStatData)
**코드 위치**: `CharacterStatDataRow.h:104-107`
```cpp
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float PhysicalDamage = 0; // 캐릭터 기본 공격력
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float MagicalDamage = 0; // 캐릭터 기본 마법 공격력
```
- 캐릭터별 기본 PhysicalDamage, MagicalDamage 값
- DataTable에서 캐릭터별로 정의 (예: 힐다, 바란 등 각각 다른 기본값)
#### 2단계: 1차 스탯 반영
**코드 위치**: `WSCharacterPlayer.cpp:3214-3245 (UpdatePrimaryStats)`
- **Str (힘)** → 평타 피해율 (NormalDamagePer), 물리 스킬 피해율에 영향
```cpp
CharacterSet->SetNormalDamagePer(NormalDamagePerCurve->Eval(PrimarySet->GetStr()));
CharacterSet->SetPhysicalSkillPer(PhysicalSkillPerCurve->Eval(PrimarySet->GetStr()));
```
- **Int (지능)** → 마법 스킬 피해율에 영향
```cpp
CharacterSet->SetMagicalSkillPer(MagicalSkillPerCurve->Eval(PrimarySet->GetInt()));
```
- **Dex (민첩)** → 공격 속도, 이동 속도에 영향
```cpp
CharacterSet->SetAttackSpeedPer(AttackSpeedPerCurve->Eval(PrimarySet->GetDex()));
```
- **커브 테이블**: `WSData->PrimaryStat` 커브 테이블에서 1차 스탯 값 → 백분율 변환
#### 3단계: 장비 효과 적용
**코드 위치**: `WSCharacterPlayer.cpp:3805-3806, 4018-4022`
```cpp
// 장비 랜덤 옵션으로 PhysicalDamage, MagicalDamage 증가
AttrValueMap.Add(UCharacterSet::GetPhysicalDamageAttribute(),
FItemHelper::CalculateOption(EquipItem, EItemOption::PhysicalDamageInc));
AttrValueMap.Add(UCharacterSet::GetMagicalDamageAttribute(),
FItemHelper::CalculateOption(EquipItem, EItemOption::MagicalDamageInc));
// 패시브 스탯 (PhysicalDamagePer, MagicalDamagePer) 백분율 적용
float PhysicalDamagePer = AbilitySystemComponent->GetNumericAttribute(
UPassiveSet::GetPhysicalDamagePerAttribute()) * 0.01f;
AttrValueMap[UCharacterSet::GetPhysicalDamageAttribute()] +=
AttrValueMap[UCharacterSet::GetPhysicalDamageAttribute()] * PhysicalDamagePer;
```
- 무기, 방어구, 악세서리 등 장비의 랜덤 옵션이 PhysicalDamage/MagicalDamage에 추가
- PassiveSet의 PhysicalDamagePer, MagicalDamagePer 백분율이 곱셈으로 적용
> **룬 시스템 영향** (섹션 5.4.1 참조):
> - **10201 분노**: PhysicalDamagePer +6~10%
> - **10301 폭풍**: MagicalDamagePer +6~10%
> - 이 단계에서 룬이 제공하는 패시브 스탯이 곱셈으로 적용됨
#### 4단계: Level 배율 적용
**코드 위치**: `WSDamageCalculation.cpp:316-322`
```cpp
float PhysicalDamage = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(
DamageStatics().PhysicalDamageDef, EvaluateParameters, PhysicalDamage);
PhysicalDamage = PhysicalDamage * Level; // Level 곱셈
float MagicalDamage = 0.0f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(
DamageStatics().MagicalDamageDef, EvaluateParameters, MagicalDamage);
MagicalDamage = MagicalDamage * Level; // Level 곱셈
```
- 최종 PhysicalDamage, MagicalDamage에 스킬 레벨 곱셈
- Level이 0이면 1로 처리 (라인 310-314)
#### 5단계: 공격 타입별 BaseDamage 결정
**코드 위치**: `WSDamageCalculation.cpp:543-613`
```cpp
if (EAttackType == EWSAttackType::Normal)
{
BaseDamage = PhysicalDamage;
SkillPer = NormalDamagePer;
}
else if (EAttackType == EWSAttackType::PhysicalSkill)
{
BaseDamage = PhysicalDamage;
SkillPer = PhysicalSkillPer + SkillDamagePer;
}
else if (EAttackType == EWSAttackType::MagicalSkill)
{
BaseDamage = MagicalDamage;
SkillPer = MagicalSkillPer + SkillDamagePer;
}
```
- **Normal (일반 공격)**: BaseDamage = PhysicalDamage
- **PhysicalSkill**: BaseDamage = PhysicalDamage
- **MagicalSkill**: BaseDamage = MagicalDamage
- **FixedSkill**: BaseDamage = 스킬 데이터에 정의된 고정값 (저항 무시)
#### 6단계: 던전 룰 배율 적용
**코드 위치**: `WSDamageCalculation.cpp:620-685`
```cpp
switch (DungeonRule)
{
case EDungeonRule::EnemyAtkUp: // BaseDamage *= 1.4 (몬스터가 공격자일 때)
case EDungeonRule::EnemyAtkUpPlus: // BaseDamage *= 1.6
case EDungeonRule::EnemyDefDown: // BaseDamage *= 0.8
case EDungeonRule::EnemyDefDownPlus:// BaseDamage *= 0.7
case EDungeonRule::HeadWeak: // BaseDamage *= 1.5 (헤드샷일 때)
}
```
#### 최종 공식 요약
```
최종 BaseDamage =
[캐릭터 기본값]
+ [장비 옵션 증가분]
× [1 + 패시브 스탯 백분율]
× [스킬 레벨]
× [던전 룰 배율]
```
**예시 (물리 스킬)**:
```
캐릭터 기본 PhysicalDamage: 50
장비 옵션 증가: +30
패시브 PhysicalDamagePer: 20%
스킬 레벨: 3
던전 룰: 없음
최종 BaseDamage = ((50 + 30) × 1.20) × 3 = 96 × 3 = 288
```
### 1.2 일반 공격/스킬 데미지 계산 흐름
> **코드 위치**: `WSDamageCalculation.cpp:251-1238 (Execute_Implementation)`
#### 계산 흐름 개요
```
[1] BaseDamage 계산 (위 섹션 참조)
[2] HitBox 판정 (머리/후면)
[3] 치명타 판정
[4] 둔기 배율 적용
[5] 저항 타입 결정 (공격/원소 타입별)
[6] 방어 상태 피해 감소
[7] 최종 Damage 계산
[8] 후면 공격 추가 배율
[9] 최소 데미지 보장
[10] 파티원 피해 제거
[11] 실드 → 아머 → HP 순서로 적용
```
#### 단계별 상세 설명
**[1] BaseDamage 계산** (라인 316-685)
- 위 "1.1 BaseDamage 계산 과정" 섹션 참조
- 캐릭터 기본값 + 장비 + 패시브 + Level + 던전 룰
**[2] HitBox 판정** (라인 470-510)
```cpp
// 머리/몸 판정
if (HitResult->BoneName == FName(TEXT("b_Head")))
{
IsHeadShot = true;
HitBoxRate = 1.2f + HeadAttackDamagePer * 0.01f;
HitBoxRate -= 0.5f * HeadShotDamReducePer * 0.01f; // 피격자의 머리 저항
}
else
{
HitBoxRate = 1.0f; // 몸
}
// 정면/후면 판정
IsFrontAttack = UWSAbilityBlueprintLibrary::IsFrontAttack(EffectCauser, Target, bUseOwnerRotation);
```
- **머리 기본 배율**: 1.2배
- **HeadAttackDamagePer**: 공격자의 머리 공격 피해 증가 (가산)
- **HeadShotDamReducePer**: 피격자의 머리 피해 감소 (절반만 적용)
- **후면 공격**: 이 단계에서는 HitBoxRate에 영향 없음 (후면 배율은 8단계에서 별도 적용)
> **룬 시스템 영향** (섹션 5.4.2 참조):
> - **10103 공략**: HeadAttackDamagePer +10~20% → 머리 공격 배율 1.2 → 1.3~1.4로 증가
**[3] 치명타 판정** (라인 512-527)
```cpp
if (bUseCritical && FMath::FRandRange(0.0f, 100.0f) < CriticalPer)
{
isCritical = true;
CriticalDamageRate = (CriticalDamagePer * 0.01f) + (FMath::Rand() * CriticalDamageRange);
}
```
- **CriticalPer**: 치명타 확률 (%)
- **CriticalDamagePer**: 치명타 피해 배율 (기본 150% 등)
- **CriticalDamageRange**: 치명타 피해 랜덤 범위
- **예시**: CriticalPer=30%, CriticalDamagePer=150%, Range=0.1
- 30% 확률로 치명타 발생
- 발생 시 1.5~1.6배 피해 (1.5 + random(0~0.1))
**[4] 둔기 배율** (라인 530-534)
```cpp
float BluntRate = 1.0f;
if (EAttackType == EWSAttackType::Normal && SourceTags->HasTag(FGameplayTag::RequestGameplayTag("Equip.BluntWeapon")))
{
BluntRate = 1.2f;
}
```
- 둔기 무기 + 일반 공격일 때만 1.2배
- 스킬 공격에는 적용 안 됨
**[5] 저항 타입 결정** (라인 543-613)
공격 타입별로 적용되는 저항이 다릅니다:
| 공격 타입 | Resistance 1 | Resistance 2 |
|----------|--------------|--------------|
| Normal | PhysicalResistance | RangedResistance (원거리일 경우) |
| PhysicalSkill | PhysicalResistance | ElementResistance (속성별) |
| MagicalSkill | MagicalResistance | ElementResistance (속성별) |
| FixedSkill | 없음 | 없음 (저항 무시) |
- **ElementResistance**: Fire/Poison/Water/Lightning/Holy/Dark 중 하나
- **특수 케이스**: UsePhysicalDamageUseMagicResist=true면 물리 피해도 마법 저항 적용
- **저항 상한**: 각 저항은 최대 75%까지만 적용 (라인 709-710)
> **룬 시스템 영향** (섹션 5.4.3 참조):
> - **10202 방패**: PhysicalResistancePer +2~7%
> - **10302 수호**: MagicalResistancePer +2~7%
> - 룬으로 증가된 저항은 받는 피해 감소에 직접 영향
**[6] 방어 상태 피해 감소** (라인 769-795)
```cpp
if (IsFrontAttack && TargetTags->HasTag(FGameplayTag::RequestGameplayTag("Character.State.Blocking")))
{
if (EAttackType == EWSAttackType::Normal || EAttackType == EWSAttackType::PhysicalSkill)
{
Damage *= (1 - BlockedPhysicalDamageReducePer * 0.01f);
}
else if (EAttackType == EWSAttackType::MagicalSkill)
{
Damage *= (1 - BlockedMagicalDamageReducePer * 0.01f);
}
}
```
- **정면 + 방어 자세**일 때만 적용
- BlockedPhysicalDamageReducePer: 기본 100% (물리 공격 완전 방어)
- BlockedMagicalDamageReducePer: 기본 90% (마법 공격 90% 방어)
- **후면 공격은 방어 불가**
**[7] 최종 Damage 계산** (라인 706-718)
```cpp
// 저항 최대 75% 제한
ResistancePer1 = FMath::Min(ResistancePer1, 75.0f);
ResistancePer2 = FMath::Min(ResistancePer2, 75.0f);
// 몬스터 또는 Armor가 0일 경우
if (TargetTags->HasTag(TagEnemy) || Armor <= 0.0f)
{
Damage = Floor(BaseDamage * HitBoxRate * (SkillPer * 0.01) *
((1 - ResistancePer1 * 0.01) * (1 - ResistancePer2 * 0.01) * (1 - DamageReductionPer * 0.01)) *
CriticalDamageRate * (1 - TakeDamageReductionPer * 0.01) * (1 + TakeDamageIncreasePer * 0.01));
}
// Armor가 있을 경우 (플레이어)
else
{
Damage = Floor((BaseDamage * BluntRate) * HitBoxRate * (SkillPer * 0.01) *
((1 - ResistancePer1 * 0.01) * (1 - ResistancePer2 * 0.01) * (1 - DamageReductionPer * 0.01)) *
CriticalDamageRate * (1 - TakeDamageReductionPer * 0.01) * (1 + TakeDamageIncreasePer * 0.01));
}
```
**공식 분해**:
1. `BaseDamage * BluntRate` - 기본 피해 × 둔기 배율
2. `× HitBoxRate` - 머리/몸 배율
3. `× (SkillPer * 0.01)` - 스킬 피해율 (NormalDamagePer, PhysicalSkillPer 등)
4. `× (1 - ResistancePer1 * 0.01)` - 1차 저항 (물리/마법)
5. `× (1 - ResistancePer2 * 0.01)` - 2차 저항 (원소/원거리)
6. `× (1 - DamageReductionPer * 0.01)` - 방어력에 의한 피해 감소
7. `× CriticalDamageRate` - 치명타 배율 (크리티컬 아니면 1.0)
8. `× (1 - TakeDamageReductionPer * 0.01)` - 피격자의 받는 피해 감소
9. `× (1 + TakeDamageIncreasePer * 0.01)` - 피격자의 받는 피해 증가
10. `Floor()` - 소수점 버림
**[8] 후면 공격 추가 배율** (라인 793)
```cpp
if (!IsFrontAttack && bUseTargetHitBox)
{
Damage *= (BackAttackDamagePer * 0.01f);
}
```
- **후면 공격**일 때 BackAttackDamagePer 백분율 곱셈 (누적)
- HitBoxRate와는 별도로 적용
**[9] 최소 데미지 보장** (라인 763-766)
```cpp
if (Damage < 1.0f && bUseDungeonRule)
{
Damage = 1.0f;
}
```
- 던전 룰이 적용될 때만
- 최소 1 데미지 보장
- 지속 피해에는 적용되지 않음
**[10] 파티원 피해 제거** (라인 850-868)
```cpp
if (IsTargetParty)
{
Damage = 0.0f; // 파티원 간 피해 완전 차단
}
```
- 같은 파티원에게는 피해 0
- 피격 이후 효과도 적용 안 됨
- 지역 효과(독 지대 등)는 여전히 적용됨
**[11] 실드 → 아머 → HP 적용** (라인 883-1047)
**실드 먼저 소모** (라인 883-888):
```cpp
ShieldDamage = Clamp(DamageNoResist, 0, Shield); // 저항 무시 피해로 계산
if (Shield > 0) {
Damage = Clamp(Damage - ShieldDamage, 0, Damage);
Shield -= ShieldDamage;
}
```
- 실드는 저항을 무시한 DamageNoResist로 계산
- 실드로 흡수한 만큼 Damage에서 차감
**아머 게이팅** (라인 1027-1035):
```cpp
if (Armor / ArmorMax > 0.5) {
DamageGating = (Armor - Damage) - (ArmorMax * 0.5);
if (DamageGating < 0) {
Damage += DamageGating; // 피해 감소
}
}
```
- 아머가 50% 이상일 때
- 한 번의 공격으로 50% 밑으로 떨어지지 않도록 보호
- **예시**: ArmorMax=100, Armor=80, Damage=40
- DamageGating = (80-40) - 50 = -10
- Damage = 40 + (-10) = 30 (10 감소)
- 최종 Armor = 80-30 = 50
**HP 적용** (라인 1038-1042):
- Armor가 0일 때만 HP에 피해
- 반죽음 상태에서는 HP에 -1씩만 적용
#### 계산 예시
**조건**:
- BaseDamage: 288 (위 예시)
- HitBoxRate: 1.2 (머리)
- SkillPer: 120% (PhysicalSkillPer)
- ResistancePer1: 30% (PhysicalResistance)
- ResistancePer2: 20% (FireResistance)
- DamageReductionPer: 15%
- CriticalDamageRate: 1.5 (치명타)
- BackAttackDamagePer: 150% (후면)
- Shield: 50
- Armor: 80 / 100
**계산**:
```
1. 기본 계산:
Damage = Floor(288 × 1.2 × 1.2 × 0.7 × 0.8 × 0.85 × 1.5)
= Floor(288 × 1.2 × 1.2 × 0.476)
= Floor(196.9)
= 196
2. 후면 배율:
Damage = 196 × 1.5 = 294
3. 실드 흡수:
Shield = 50 감소
Damage = 294 - 50 = 244
4. 아머 게이팅:
DamageGating = (80 - 244) - 50 = -214
Damage = 244 + (-214) = 30 (아머를 50으로 보호)
5. 최종:
Shield: 0
Armor: 50
HP: 변화 없음
```
### 1.3 지속 피해(DoT) 계산
> **코드 위치**: `WSDamageCalculation.cpp:427-437`
지속 피해는 일반 공격/스킬과는 별도의 계산 방식을 사용합니다.
#### DoT의 정의
- 캐릭터에게 지속적으로 피해를 주는 효과로써, 주로 스토커 스킬에 포함된다.
- 별도 명세가 없는한, 동일한 DD는 중첩되지 않고, 지속시간이 초기화 된다.
- 다른 DD끼리는 동시에 걸릴 수 있다.
- **DD는 적용 1초 후부터 피해가 발생하며, 1초 주기로 작동한다.**
#### 지속 피해 종류 및 공식
**중독 Poison**
- 유지 시간 동안 최대 체력의 n%만큼의 피해를 체력에 준다.
- 공식: `Maxhp*0.20*(1-DOTReduceRate)*(1-PoisonResistanceInc)/10`
- 10초 동안 적용되어 총 최대 체력의 20% 피해
**부식 Corrosion**
- 유지 시간 동안 방어구 최대 내구도의 n%만큼의 피해를 방어구 내구도에 준다.
- 공식: `MaxArmor*0.2*(1-DOTReduceRate)*(1-DarkResistanceInc)/10`
- **주의**: 암흑 저항(DarkResistance)이 적용됨
- 10초 동안 적용되어 총 최대 아머의 20% 피해
**화상 Burn** (중독 + 부식)
- 유지 시간 동안 최대 체력과 최대 방어구 내구도의 n%만큼의 피해를 체력과 방어구 내구도에 각각 준다.
- HP 공식: `Maxhp*0.1*(1-DOTReduceRate)*(1-FireResistanceInc)/10`
- Armor 공식: `MaxArmor*0.1*(1-DOTReduceRate)*(1-FireResistanceInc)/10`
- 10초 동안 적용되어 총 최대 체력/아머의 10% 피해
**출혈 Bleed**
- 10초 동안 1초 간격으로 체력이 -2씩 감소한다. 총 -20 체력. 출혈 저항이 없기 때문에 -2 감소는 절대값.
- 중독과의 차이점은 상대방의 최대 체력과 상관없이 총 피해량이 정해져 있다는 점.
**감전 ElectricShock** (미구현)
- 중독 효과 + 스킬을 사용할 수 없다. (일반 공격은 가능)
#### DoT 계산 예시
**조건**:
- HPMax: 1000
- DOTReducePer: 10%
- PoisonResistancePer: 25%
- 중독 지속 시간: 10초
**계산**:
```
1초당 피해 = 1000 × 0.20 × (1-0.1) × (1-0.25) / 10
= 1000 × 0.20 × 0.9 × 0.75 / 10
= 13.5
총 피해 (10초) = 13.5 × 10 = 135
```
### 1.4 힐 계산
> **코드 위치**: `WSHealCalculation.cpp:49-125`
힐은 마법 공격력 기반으로 계산됩니다.
#### 힐 계산 공식
**기본 공식** (라인 97-98):
```cpp
// 힐 = 기본 힐량 + (마법공격력 × 스킬 계수) × (인트배율)
HealMagnitude = InComingHeal * Level + (MagicalDamage * (1.0 + SkillDamagePer * 0.01)) * (MagicalSkillPer * 0.01)
```
**구성 요소**:
1. **InComingHeal**: 스킬 데이터에 정의된 기본 힐량
2. **Level**: 스킬 레벨
3. **MagicalDamage**: 시전자의 마법 공격력 (2차 스탯)
4. **SkillDamagePer**: 패시브 스킬 피해 증가 (PassiveSet)
5. **MagicalSkillPer**: 지능(Int)에 의한 마법 스킬 피해율 (CharacterSet)
#### 과치유 방지
**코드** (라인 106-108):
```cpp
float TargetMaxHP = TargetASC->GetNumericAttribute(UCharacterSet::GetHPMaxAttribute());
float TargetHP = TargetASC->GetNumericAttribute(UCharacterSet::GetHPAttribute());
float HealAmount = FMath::Min(HealMagnitude, TargetMaxHP - TargetHP);
```
- 현재 HP + HealAmount가 MaxHP를 초과하지 않도록 제한
- 과치유는 발생하지 않음
#### 힐 무효
**코드** (라인 110-113):
```cpp
if (TargetASC->HasMatchingGameplayTag(FGameplayTag::RequestGameplayTag("Effect.IgnoreHeal")))
{
HealAmount = 0.0f;
}
```
- `Effect.IgnoreHeal` 태그가 있으면 힐 완전 무효
- 특정 디버프나 상태에서 힐 차단용
#### 궁극기 게이지 충전
**코드** (라인 118-123):
```cpp
if (!SourceASC->HasMatchingGameplayTag(FGameplayTag::RequestGameplayTag("Ability.Ultimate")))
{
float UltimateCurrentvalue = InstigatorCharacter->CharacterSet->GetUltimateCurrentValue();
float UltimateMaxValue = InstigatorCharacter->CharacterSet->GetUltimateMaxValue();
InstigatorCharacter->CharacterSet->SetUltimateCurrentValue(FMath::Min(HealAmount + UltimateCurrentvalue, UltimateMaxValue));
}
```
- 궁극기 사용 중이 아닐 때만
- 실제 회복한 HealAmount만큼 궁극기 게이지 충전
- UltimateMaxValue를 초과하지 않음
#### 힐 계산 예시
**조건**:
- InComingHeal: 50 (스킬 기본 힐량)
- Level: 3
- MagicalDamage: 100
- SkillDamagePer: 15%
- MagicalSkillPer: 120%
- Target HP: 800 / 1000
**계산**:
```
1. HealMagnitude 계산:
HealMagnitude = (50 × 3) + (100 × 1.15) × 1.2
= 150 + (115 × 1.2)
= 150 + 138
= 288
2. 과치유 방지:
최대 회복 가능량 = 1000 - 800 = 200
HealAmount = Min(288, 200) = 200
3. 최종:
HP: 800 → 1000
궁극기 게이지: +200
```
---
## 2. BaseDamage 구성요소
### 2.1 1차 스탯 (Primary Stats)
> **코드 위치**: `PrimarySet.h`
캐릭터 1차 스탯의 총합은 75가 되도록 한다.
- **힘** Str - 일반 공격 과 물리 스킬 피해량 에 영향을 준다.
- **민첩** Dex - 이동 속도 와 일반 공격 속도(평타) 에 영향을 준다.
- **지능** Int - 마법 스킬 시전속도 와 마법 스킬 피해량 에 영향을 준다.
- **체질** Con - 최대 체력 과 받는 지속 피해 감소 그리고 최대 지구력 에 영향을 준다.
- **지혜** Wis - 최대 마나 와 마나 소비량 에 영향을 준다.
### 2.2 2차 스탯 (Secondary Stats)
> **코드 위치**: `CharacterSet.h`
#### 기본 스탯
- 체력 HP
- 최대 체력 HPMax
- 마나 MP
- 최대 마나 MPMax
- 지구력 Stamina // 능력치 정보에서 안나옴
- 최대 지구력 StaminaMax
- 실드 Shield // 피해 흡수, 저항 무시
#### 피해 관련
- 물리 피해 PhysicalDamage
- 마법 피해 MagicalDamage
- 일반 공격 피해율 NormalDamagePer
- 물리 스킬 피해율 PhysicalSkillPer
- 마법 스킬 피해율 MagicalSkillPer
- 고정 스킬 피해율 FixedSkillPer
#### 방어 관련
- 방어력 Defense
- 고정 방어력 FixedDefense // 방어력 증가(%)의 영향을 받지 않는 방어력
- 방어력 비율 DefensePer
- 피해 감소율 DamageReductionPer // Defense에 의한 대미지 감소
- 방어구 내구도 Armor // 인게임 용어는 Armor Durability
- 최대 방어구 내구도 ArmorMax
- 콤비네이션 아머 CombinationArmor // 몬스터 전용
#### 속도 관련
- 이동속도 WalkSpeed
- 이동속도 비율 WalkSpeedPer
- 이동속도 수정값 MoveSpeedModify // 장비에 의해 변경
- 공격속도 AttackSpeedPer
- 스킬 시전 속도 SkillCastSpeedPer
#### 마나 관련
- 마나 회복 ManaRegen
- 마나 회복 비율 MPRegenPer
- 마나 소비 감소 // SkillCostReducePer
- 마나 쉴드 대미지 감소 MPDamageReducePer
#### 치명타 관련
- 치명타 확률 CriticalPer
- 치명타 피해 CriticalDamagePer
- 치명타 피해 감소 CriticalDamageReducePer
- 치명타 피해 범위 CriticalDamageRange
#### 특수 피해
- 후방 공격 피해율 BackAttackDamagePer
- 머리 공격 피해율 HeadAttackDamagePer // 때리는 입장
- 머리 피해 감소 HeadShotDamReducePer // 맞는 입장
- 방어 무시 피해율 IgnoreArmorDamagePer
- 방어 무시 피해의 아머 피해율 IgnoreArmorDamageToArmorPer
#### 저항
- 물리 저항률 PhysicalResistancePer
- 투사체 저항률 RangedResistancePer
- 마법 저항률 MagicalResistancePer
- 화염 저항률 FireResistancePer
- 독 저항률 PoisonResistancePer
- 물 저항률 WaterResistancePer
- 번개 저항률 LightningResistancePer
- 빛 저항률 HolyResistancePer
- 암흑 저항률 DarkResistancePer
- 지속 피해 저항률 DOTReducePer
#### 브레이크다운 시스템
- 브레이크다운 Breakdown // 브레이크다운 게이지 현재값
- 브레이크다운 최대값 BreakdownMax // 브레이크다운 게이지 최대값
- 브레이크다운 스턴 시간 BreakdownStunTime // 브레이크다운 발동 시 스턴 지속 시간
- 브레이크다운 리셋 시간 BreakdownResetTime // 브레이크다운 게이지 리셋 시간
#### 궁극기
- 궁극기 현재값 UltimateCurrentValue // 궁극기를 사용하기 위해서 충전해야 하는 포인트
- 궁극기 최대값 UltimateMaxValue
- 궁극기 회복 비율 UltimateRecoveryPer
#### 기타
- 장착 가능 장비 EquipableTypes
- 무기 종류: 검, 활, 지팡이, 대검, 단검, 둔기 // 1종을 할당
- 갑옷 종류: 천, 경갑, 중갑 // 2종을 할당
- 스킬 쿨타임 감소율 SkillCoolTimeReducePer
- 스킬 비용 감소율 SkillCostReducePer
- 가하는 피해량 감소 TakeDamageReductionPer // 리옌의 연화 디버프
- 가하는 피해량 증가 TakeDamageIncreasePer // 피해량 증가 스크롤
### 2.3 패시브 스탯 (비율 수정자)
> **코드 위치**: `PassiveSet.h`
패시브 스탯은 장비, 스킬, 퍽, **룬** 등을 통해 캐릭터의 능력치를 **백분율(%)로 수정**하는 속성들입니다. 주로 장비 랜덤 옵션, 스킬 효과, 캐릭터별 퍽(Perk) 시스템, **룬 시스템**에서 사용됩니다.
> **룬 시스템 영향** (섹션 5.3 참조):
> 룬 시스템은 PassiveSet 속성을 직접 수정하여 전투 능력을 강화합니다. 주요 룬 영향 속성:
> - PhysicalDamagePer, MagicalDamagePer, SkillDamagePer (피해 증가)
> - SkillCoolTimeReducePer, ManaCostPer, CastingTimePer (스킬 코스트)
> - NormalEnemyDamagePer, EliteEnemyDamagePer, BossEnemyDamagePer (몬스터 타입별)
> - APPer, PotionEffectPer, ThrowItemImpactRangePer 등
#### 공통 패시브 스탯 (PassiveSet.h:125-260)
**피해 관련**:
- PhysicalDamagePer // 물리 피해 증가율
- MagicalDamagePer // 마법 피해 증가율
- ArmorAttackDamagePer // 방어구 공격 피해 증가율
- SkillDamagePer // 스킬 피해 증가율
- TakenSkillDamagePer // 받는 스킬 피해 증가율
- InflictDamagePerOnStunTarget // 기절 대상에게 가하는 피해 증가율
- NormalEnemyDamagePer // 일반 몬스터에게 가하는 피해 증가율
- EliteEnemyDamagePer // 엘리트 몬스터에게 가하는 피해 증가율
- BossEnemyDamagePer // 보스 몬스터에게 가하는 피해 증가율
**방어 관련**:
- DefensePer // 방어력 증가율
- BreakArmorDefensePer // 방어구 파괴 방어 증가율
**속도 관련**:
- AttackSpeedPer // 공격 속도 증가율
- WalkSpeedPer // 이동 속도 증가율
**체력/마나/지구력 관련**:
- HPPer // 최대 체력 증가율
- MPPer // 최대 마나 증가율
- APPer // 지구력 증가율 (Armor Points)
- BlockingStaminaRate // 방어 시 지구력 소모 비율
**스킬/마나 코스트 관련**:
- ManaCostPer // 마나 소비 증가율 (음수면 감소)
- CastingTimePer // 시전 시간 증가율 (음수면 감소)
- CooldownTimePer // 쿨다운 시간 증가율 (음수면 감소)
**상태이상 관련**:
- TakenCCDurationTimePer // 받는 CC 지속 시간 증가율
**인터랙션 관련**:
- InteractionTimePer // 상호작용 시간 증가율 (음수면 감소)
- InteractionTakenDamagePer // 상호작용 중 받는 피해 증가율
- ChestInteractionTimePer // 상자 상호작용 시간 증가율
- DoorInteractionTimePer // 문 상호작용 시간 증가율
**어그로 및 스텔스**:
- AggroPer // 어그로 증가율
- CrouchWalkSoundPer // 웅크린 이동 소리 증가율
**부활 관련**:
- ReviveHPBonusRate // 부활 시 체력 보너스 비율
- ReviveTime // 부활 시간
**아이템 효과**:
- PotionEffectPer // 포션 효과 증가율
- ThrowItemImpactRangePer // 투척 아이템 범위 증가율
- ThrowEffectDurationPer // 투척 효과 지속 시간 증가율
- StatueEffectPer // 조각상 효과 증가율
**NPC 관련**:
- AttackDamagePerOnNpcKill // NPC 처치 시 공격 피해 증가율
#### 캐릭터별 전용 퍽 스탯 (PassiveSet.h:263-461)
각 스토커 캐릭터는 전용 퍽 스탯을 보유하고 있습니다:
- **Hilda** (힐다): 7개의 전용 퍽 (라인 265-292)
- **Urud** (우루드): 6개의 전용 퍽 (라인 297-320)
- **Nave** (네이브): 10개의 전용 퍽 (라인 325-364)
- **Baran** (바란): 8개의 전용 퍽 (라인 369-400)
- **Rio** (리오): 8개의 전용 퍽 (라인 405-436)
- **Clad** (클라드): 5개의 전용 퍽 (라인 441-460)
#### 범용 퍽 슬롯 (PassiveSet.h:466-488)
- Perk1 ~ Perk8: 범용 퍽 값 저장용 (용도는 게임플레이 효과에서 정의)
---
## 3. 데미지 수정자
### 3.1 공격 타입 (AttackType)
> **코드 위치**: `SkillDataRow.h:13-21`
- 일반 공격(평타) Normal = 0
- 물리 스킬 PhysicalSkill = 1
- 마법 스킬 MagicalSkill = 2
- 고정 스킬 FixedSkill = 3 // 저항 무시 스킬용
- None = 4
### 3.2 원거리 타입 (RangedType)
- 평타가 원거리인지 아닌지를 판단
- 원거리 공격일 경우 RangedResistancePer 저항이 적용됨
### 3.3 원소 타입 (ElementType)
> **코드 위치**: `SkillDataRow.h:24-33`
- None = 0 // 무속성
- 화염 Fire = 1
- 독 Poison = 2
- 물 Water = 3
- 번개 Lightning = 4
- 빛 Holy = 5
- 암흑 Dark = 6
### 3.4 피해 종류 (DamageStatics)
- 일반 피해 NormalDamage
- 물리 피해 PhysicalDamage
- 마법 피해 MagicalDamage
- 치명 피해 CriticalDamage
- 후방 피해 BackAttackDamage
- 방어 무시 피해 IgnoreArmorDamage
- 갑옷 피해 IgnoreArmorDamageToArmor
- 머리 피해 HeadAttackDamage
### 3.5 저항 종류 (가급적 갑옷에 부여)
- MP 피해 저항 MPDamageReducePer
- 머리 피해 저항 HeadShotDamReducePer
- 지속 피해 저항 DOTReducePer
- 물리 저항 PhysicalResistancePer
- 마법 저항 MagicalResistancePer
- 원거리 저항 RangedResistancePer
- 화염 저항 FireResistancePer
- 독 저항 PoisonResistancePer
- 물 저항 WaterResistancePer
- 번개 저항 LightningResistancePer
- 빛 저항 HolyResistancePer
- 암흑 저항 DarkResistancePer
**저항 상한**: 모든 저항은 최대 75%까지만 적용됨
### 3.6 피격 부위 배율 (HitBoxRate)
> **코드 위치**: `WSDamageCalculation.cpp:473-510`
> **실제 구현**: 후면 공격 배율은 HitBoxRate가 아닌 BackAttackDamagePer 패시브로 조정됨
- **정면 공격** (IsFrontAttack = true)
- 머리 (IsHeadShot = true): `HitBoxRate = 1.2 + HeadAttackDamagePer * 0.01 - 0.5 * HeadShotDamReducePer * 0.01`
- 몸 (IsHeadShot = false): `HitBoxRate = 1.0`
- **후면 공격** (IsFrontAttack = false)
- 머리 (IsHeadShot = true): `HitBoxRate = 1.2 + HeadAttackDamagePer * 0.01 - 0.5 * HeadShotDamReducePer * 0.01`
- 몸 (IsHeadShot = false): `HitBoxRate = 1.0`
- **후면 추가 배율**: 최종 데미지에 `BackAttackDamagePer * 0.01` 곱셈 (코드 라인 793)
### 3.7 둔기 배율 (BluntRate)
> **코드 위치**: `WSDamageCalculation.cpp:530-534`
- 둔기 유형의 무기는 **1.2배** 데미지 (태그: `Equip.BluntWeapon`)
- 일반 공격(Normal) 타입일 때만 적용
### 3.8 쇼크 효과 (ShockMontageEffect)
플레이어가 쇼크 상태에 빠질 때 아래 몽타주 중 1개가 재생된다. (시간이 다름)
- 갑옷 완파 GE_ShockMotion_ArmorDestroy_Complete
- 갑옷 반파 GE_ShockMotion_ArmorDestroy_Partial
- 쇼크 대 GE_ShockMotion_Heavy
- 쇼크 중 GE_ShockMotion_Medium
- 쇼크 소 GE_ShockMotion_Weak
---
## 4. 특수 시스템
### 4.1 상태 이상(CC) & 능력치 하향(DeBuff)
#### 상태 이상CC 정의
- 캐릭터의 행동을 제한하거나 무력화 시키는 효과로써, 주로 스토커 스킬에 포함된다.
- 일반적으로 캐릭터들의 Motion Factor를 제어하며, 지속 시간을 보유하고 있다.
- 지속 시간의 표현을 위해 모션과 이펙트가 사용될 수 있다.
- GameplayTag로 `Character.State.*` 형태로 관리됨
#### 상태 이상CC의 종류
- **충격 Shock** (구현됨)
- 대상의 공격 모션을 중단 시킨다.
- **기절 Stun** (구현됨)
- 충격 Shock + 이동을 제한한다.
- **속박 Snare** (구현됨)
- 대상의 이동을 제한한다.
- **끌어당김 Grab** (구현됨)
- 기절 Stun + 시전자 방향으로 강제 이동시킨다.
- **밀쳐냄 KnockBack** (구현됨)
- 기절 Stun + 시전자의 반대 방향으로 강제 이동 시킨다.
- 이동 거리는 피격 대상의 위치를 기준으로 계산된다.
- **공포 Flee** (미구현)
- 충격 Shock + 시전자의 반대 방향으로 느리게 이동한다.
- 효과 지속시간 동안 피격 대상은 공격 행위를 할 수 없다.
- **수면 Sleep** (미구현)
- 기절 Stun과 같은 효과지만, 유지 시간 동안 대상이 다시 피격되면 해제 된다.
- 일반적으로 기절 Stun 보다는 유지 시간이 길다.
#### 능력치 하향DeBuff의 정의
- 캐릭터가 가진 능력치를 일시적으로 하향시키는 효과로써, 주로 스토커 스킬에 포함된다.
- 별도 명세가 없는한, 동일한 DeBuff는 중첩되지 않고, 지속시간이 초기화 된다.
- 다른 DeBuff끼리는 동시에 걸릴 수 있다.
#### 능력치 하향DeBuff의 종류
- **둔화 Slow** (구현됨)
- 유지 시간 동안 이동 속도가 n% 낮아진다.
- `WalkSpeedPer` 속성으로 구현
- **무장 해제 Disarm** (미구현)
- 유지 시간 동안 공격력이 n% 낮아진다.
### 4.2 방어 지구력 시스템
> **코드 위치**: `WSDamageCalculation.cpp:769-795` (방어 시스템)
> **Blueprint 경로 확인됨**: `D:\Work\WorldStalker\WorldStalker\Content\Blueprints\Abilities\GE_BlockingStateStamina.uasset`
#### 방어 상태 유지에 따른 효과
- **지구력 소모**
- BP경로: `/Game/Blueprints/Abilities/GE_BlockingStateStamina`
- 현재 설정 값: 0.2초 마다 -0.5 지구력
- **주의**: Blueprint 파일은 바이너리 형식이므로 설정값은 에디터에서 확인 필요
- **이동 속도 감소** (걷기만 가능하며 뛸 수 없다)
- BP경로: `/Game/Blueprints/Abilities/GE_AttackBlockedWalkSpeedDown`
- 현재 설정 값: 원래 걷는 속도의 70% 수준으로 이동한다.
- **주의**: Blueprint 파일은 바이너리 형식이므로 설정값은 에디터에서 확인 필요
- **방어 유지 가능 스토커**: 힐다, 바란, 클라드 (카지모르드는 아님)
#### 방어 성공에 따른 지구력 감소 값
- **근거리 일반 공격 방어**
- BP경로: `/Game/Blueprints/Abilities/GE_AttackBlocked`
- 현재 설정 값: 성공 시 -27.0 지구력
- **주의**: Blueprint 파일은 바이너리 형식이므로 설정값은 에디터에서 확인 필요
- **원거리 일반 공격 방어**
- BP경로: `/Game/Blueprints/Abilities/GE_AttackBlocked_Projectile`
- 현재 설정 값: 성공 시 -32.0 지구력
- **주의**: Blueprint 파일은 바이너리 형식이므로 설정값은 에디터에서 확인 필요
- **마법 공격 방어**
- BP경로: `/Game/Blueprints/Abilities/GE_AttackBlocked_Magic`
- 현재 설정 값: 성공 시 -35.0 지구력
- **주의**: Blueprint 파일은 바이너리 형식이므로 설정값은 에디터에서 확인 필요
#### 방어 피해 감소
> **코드 위치**: `WSDamageCalculation.cpp:769-795`
- **정면 방어 시** (IsFrontAttack && Character.State.Blocking 태그 보유)
- 일반 공격 (Normal): `Damage * (1 - BlockedPhysicalDamageReducePer * 0.01)` 감소
- 물리 스킬 (PhysicalSkill): `Damage * (1 - BlockedPhysicalDamageReducePer * 0.01)` 감소
- 마법 스킬 (MagicalSkill): `Damage * (1 - BlockedMagicalDamageReducePer * 0.01)` 감소
- **후면 공격은 방어 불가**
#### 지구력 자동 회복
- **전제**: 뛰는 상태 or 방어 상태가 아니어야 한다.
- 전제를 만족하고 n초 후에 m씩 지구력이 자동 회복 된다.
- BP경로: `/Game/Blueprints/Abilities/GE_StaminaRegen`
- **주의**: Blueprint 파일은 바이너리 형식이므로 설정값은 에디터에서 확인 필요
### 4.3 반죽음 (HalfDeath)
> **코드 위치**: `WSDamageCalculation.cpp:928-932`, `WSCharacterBase.h:178-180`
> **GameplayTag**: `Character.State.HalfDeath`
#### 반죽음의 정의
- 스토커의 체력HP = 0 이되면 n초 동안 반죽음 상태가 된다. 방어구 내구도와는 상관이 없다.
- 반죽음 상태가 되면 천천히 기면서 이동만 할 수 있고, 그 외 다른 행동(ex 공격)은 할 수 없다.
- 반죽음 상태가 없는 경우는 아래와 같다:
- 파티원이 없거나 or 생존한 파티원이 없을 경우 즉, 혼자 있을 경우에는 HP = 0이되면 바로 사망.
- `CanHalfDie()` 함수로 판별 (WSCharacterBase.h:178)
#### 반죽음 상태에서의 피해
- **피해량과는 상관 없이 총 3회의 피격을 견딜 수 있다.**
- 코드: 반죽음 상태에서는 피격 시 HP에 -1씩만 적용 (WSDamageCalculation.cpp:930)
- 상태 이상, 능력치 하향, 지속 피해 효과가 있다면 즉시 해제 된다.
- **파티원의 공격은 적용되지 않음** (코드 라인 928: `IsTargetParty` 체크)
#### 반죽음 → 사망 판정
- 반죽음 유지 시간이 모두 지나거나 or 피격을 3회 이상 받으면 사망 상태가 된다.
#### 반죽음 → 부활 판정
- 사망 판정을 받기 전에 파티원이 근처에 와서 F키를 눌러 부활시켜주면 된다. (일정 시간 필요)
- 반죽음 이전에 방어구 내구도가 남아 있었다면 이를 보존시켜준다.
---
## 5. 룬 시스템
> **코드 위치**:
> - `WSGameplayAbility.h:209, 268` - 룬 데이터 조회 함수
> - `WSGameplayAbility.cpp:1525-1550` - 룬 데이터 검색 구현
> - **DT_Rune, DT_RuneGroup** DataTable 어셋 (DataTable.json 파일에 익스포트됨)
### 5.1 룬 시스템 개요
룬은 플레이어가 장착하여 전투 능력과 탐험 능력을 강화하는 장비 시스템입니다. 각 룬은 레벨 1부터 5까지 업그레이드가 가능하며, 레벨이 올라갈수록 효과가 강화됩니다.
#### 기본 메커니즘
- **장착 슬롯**: 총 5개의 룬 슬롯 보유
- **레벨 시스템**: 각 룬은 Lv.1 ~ Lv.5까지 업그레이드 가능
- **그룹 구조**: 5개 그룹으로 분류 (전투, 스킬, 장비, 보조, 모험)
- **선택 제약**: Main 그룹 1개 + Sub 그룹 1개 선택
#### 룬 ID 체계
룬 ID는 5자리 숫자로 구성됩니다:
```
XYZNN
X = 그룹 번호 (1:전투, 2:스킬, 3:장비, 4:보조, 5:모험)
Y = 라인 타입 (1:Core, 2:Sub1, 3:Sub2)
Z = 라인 내 순번
NN = 추가 식별자 (보통 01)
```
**예시**: `10201` = 전투 그룹(1), Sub1 라인(2), 첫 번째 룬(01)
### 5.2 룬 선택 규칙
#### 그룹 선택
1. **Main 그룹**: 5개 그룹 중 1개 선택
- Core Line, Sub 1Line, Sub 2Line 모두 선택 가능 (3개 룬)
2. **Sub 그룹**: Main이 아닌 다른 그룹 중 1개 선택
- **제약**: Core Line 선택 불가
- Sub 1Line, Sub 2Line만 선택 가능 (2개 룬)
#### 선택 예시
**Main: 전투(Battle), Sub: 스킬(Skill)**
```
선택 가능한 룬:
- 10101 (전투-Core-1)
- 10102 (전투-Core-2)
- 10103 (전투-Core-3)
- 20201 (스킬-Sub1-1)
- 20301 (스킬-Sub2-1)
총 5개 룬 장착 가능
```
**Main: 장비(Equipment), Sub: 보조(Assist)**
```
선택 가능한 룬:
- 30101 (장비-Core-1)
- 30102 (장비-Core-2)
- 30103 (장비-Core-3)
- 40201 (보조-Sub1-1)
- 40301 (보조-Sub2-1)
총 5개 룬 장착 가능
```
### 5.3 룬 그룹 및 효과
#### 5.3.1 전투 그룹 (Battle, 10xxx)
**Core Line** (10101~10103):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 10101 | 충전 | 궁극기 게이지 회복량 증가 | UltimateRecoveryPer | Lv.1: +15% → Lv.5: +30% |
| 10102 | 진격 | 공격 적중 시 이동 속도 증가 | GA_Rune_10102 | 조건부 효과 (Blueprint) |
| 10103 | 공략 | 머리 공격 피해 증가 | HeadAttackDamagePer | Lv.1: +10% → Lv.5: +20% |
**Sub 1Line** (10201~10202):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 10201 | 분노 | 물리 피해 증가 | PhysicalDamagePer | Lv.1: +6% → Lv.5: +10% |
| 10202 | 방패 | 물리 저항 증가 | PhysicalResistancePer | Lv.1: +2% → Lv.5: +7% |
**Sub 2Line** (10301~10302):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 10301 | 폭풍 | 마법 피해 증가 | MagicalDamagePer | Lv.1: +6% → Lv.5: +10% |
| 10302 | 수호 | 마법 저항 증가 | MagicalResistancePer | Lv.1: +2% → Lv.5: +7% |
#### 5.3.2 스킬 그룹 (Skill, 20xxx)
**Core Line** (20101~20103):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 20101 | 저주 | 스킬 적중 시 지연 피해 | GA_Rune_20101 | 조건부 효과 (Blueprint) |
| 20102 | 침식 | 저주 중첩당 스킬 피해 증가 | GA_Rune_20102 | 조건부 효과 (Blueprint) |
| 20103 | 활기 | 마나 높을 때 스킬 피해 증가 | GA_Rune_20103 | 조건부 효과 (Blueprint) |
**Sub 1Line** (20201~20203):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 20201 | 파괴 | 스킬 피해 증가 | SkillDamagePer | Lv.1: +6% → Lv.5: +10% |
| 20202 | 왜곡 | 스킬 쿨타임 감소 | SkillCoolTimeReducePer | Lv.1: +15% → Lv.5: +25% |
| 20203 | 절약 | 스킬 마나 소모 감소 | ManaCostPer | Lv.1: -25% → Lv.5: -50% |
**Sub 2Line** (20301~20302):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 20301 | 명상 | 마나 회복량 증가 | MPRegenPer | Lv.1: +28% → Lv.5: +70% |
| 20302 | 영창 | 스킬 시전 속도 증가 | CastingTimePer | Lv.1: -15% → Lv.5: -30% |
#### 5.3.3 장비 그룹 (Equipment, 30xxx)
**Core Line** (30101~30103):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 30101 | 공허 | 비어있는 장비 슬롯당 피해 증가 | GA_Rune_30101 | Lv.1: +2%/슬롯 → Lv.5: +4%/슬롯 |
| 30102 | 견고 | 갑옷 내구도 증가 | APPer | Lv.1: +10% → Lv.5: +50% |
| 30103 | 완벽 | 장비 슬롯 다 채우면 방어력 증가 | GA_Rune_30103 | Lv.1: +7% → Lv.5: +18% |
**Sub 1Line** (30201~30202):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 30201 | 용사 | 검/단검/대검 피해 증가 | GA_Rune_30201 | Lv.1: +8% → Lv.5: +12% |
| 30202 | 투사 | 지팡이/활/둔기 피해 증가 | GA_Rune_30202 | Lv.1: +8% → Lv.5: +12% |
**Sub 2Line** (30301~30303):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 30301 | 신속 | 천 방어구당 시전 속도 증가 | GA_Rune_30301 | Lv.1: +3%/갑옷 → Lv.5: +5%/갑옷 |
| 30302 | 정밀 | 경갑 방어구당 치명타 확률 증가 | GA_Rune_30302 | Lv.1: +1%/갑옷 → Lv.5: +3%/갑옷 |
| 30303 | 강인 | 중갑 방어구당 방어력 증가 | GA_Rune_30303 | Lv.1: +1.5%/갑옷 → Lv.5: +6.5%/갑옷 |
#### 5.3.4 보조 그룹 (Assist, 40xxx)
**Core Line** (40101~40102):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 40101 | 부활 | 쓰러진 상태에서 자동 부활 1회 | ReviveTime | Lv.1: 25초 → Lv.5: 5초 |
| 40102 | 만전 | 던전 진입 시 기본 궁극기 획득 | GA_Rune_40102 | Lv.1: 25% → Lv.5: 50% |
**Sub 1Line** (40201~40202):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 40201 | 면역 | 물약 사용 시 물리/마법 저항 증가 | GA_Rune_40201 | 20초간, Lv.1: +10% → Lv.5: +20% |
| 40202 | 기습 | 투척 아이템 사용 시 공격 속도 증가 | GA_Rune_40202 | 20초간, Lv.1: +10% → Lv.5: +20% |
**Sub 2Line** (40301~40302):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 40301 | 효율 | 물약 효과 증가 (지속 시간 제외) | PotionEffectPer | Lv.1: +25% → Lv.5: +50% |
| 40302 | 폭발 | 투척 아이템 범위 증가 | ThrowItemImpactRangePer | Lv.1: +25% → Lv.5: +50% |
#### 5.3.5 모험 그룹 (Adventure, 50xxx)
**Core Line** (50101~50103):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 50101 | 선물 | 잠긴 보물 상자 표시, 오픈 시 최대 HP 증가 | GA_Rune_50101 | 최대 10회, Lv.1: +11 → Lv.5: +22 |
| 50102 | 누적 | 몬스터 처치시 피해 증가 (누적) | GA_Rune_50102 | Lv.1: 1.1%/최대 11% → Lv.5: 1.5%/최대 15% |
| 50103 | 탐험 | 조명석 사용 중 지구력 소모량 감소 | GA_Rune_50103 | Lv.1: -30% → Lv.5: -60% |
**Sub 1Line** (50201~50202):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 50201 | 학살 | 일반 몬스터 대상 피해 증가 | NormalEnemyDamagePer | Lv.1: +20% → Lv.5: +30% |
| 50202 | 퇴치 | 엘리트 몬스터 대상 피해 증가 | EliteEnemyDamagePer | Lv.1: +16% → Lv.5: +20% |
**Sub 2Line** (50301~50303):
| 룬 ID | 이름 | 효과 | 속성 | 레벨별 수치 |
|-------|------|------|------|-------------|
| 50203 | 격퇴 | 보스 몬스터 대상 피해 증가 | BossEnemyDamagePer | Lv.1: +11% → Lv.5: +15% |
| 50301 | 기대 | 상자 열기 시간 감소 | ChestInteractionTimePer | Lv.1: -25% → Lv.5: -50% |
| 50302 | 도적 | 문 열기/닫기 시간 감소 | DoorInteractionTimePer | Lv.1: -25% → Lv.5: -50% |
| 50303 | 축복 | 석상 버프 효과 증가 | StatueEffectPer | Lv.1: +50% → Lv.5: +100% |
### 5.4 룬이 전투 로직에 미치는 영향
#### 5.4.1 BaseDamage 계산 단계 (섹션 1.1 참조)
룬은 **3단계: 장비 효과 적용**에서 PassiveSet 속성을 통해 영향을 줍니다:
```cpp
// WSCharacterPlayer.cpp:4018-4022
// PassiveSet의 PhysicalDamagePer, MagicalDamagePer 백분율이 곱셈으로 적용
float PhysicalDamagePer = AbilitySystemComponent->GetNumericAttribute(
UPassiveSet::GetPhysicalDamagePerAttribute()) * 0.01f;
AttrValueMap[UCharacterSet::GetPhysicalDamageAttribute()] +=
AttrValueMap[UCharacterSet::GetPhysicalDamageAttribute()] * PhysicalDamagePer;
```
**영향을 주는 룬**:
- **10201 분노**: PhysicalDamagePer +6~10% → 물리 공격력 증가
- **10301 폭풍**: MagicalDamagePer +6~10% → 마법 공격력 증가
- **20201 파괴**: SkillDamagePer +6~10% → 스킬 피해 증가
**예시 계산**:
```
[룬 적용 전]
캐릭터 기본 PhysicalDamage: 50
장비 옵션 증가: +30
패시브 PhysicalDamagePer: 0%
→ 최종 PhysicalDamage = (50 + 30) × 1.0 = 80
[10201 분노 Lv.5 장착 후]
캐릭터 기본 PhysicalDamage: 50
장비 옵션 증가: +30
패시브 PhysicalDamagePer: 10% (룬 효과)
→ 최종 PhysicalDamage = (50 + 30) × 1.10 = 88 (+10% 증가)
```
#### 5.4.2 HitBox 판정 단계 (섹션 1.2 [2] 참조)
룬은 **머리 공격 배율 계산**에 직접 영향을 줍니다:
```cpp
// WSDamageCalculation.cpp:470-510
if (HitResult->BoneName == FName(TEXT("b_Head")))
{
IsHeadShot = true;
HitBoxRate = 1.2f + HeadAttackDamagePer * 0.01f;
HitBoxRate -= 0.5f * HeadShotDamReducePer * 0.01f;
}
```
**영향을 주는 룬**:
- **10103 공략**: HeadAttackDamagePer +10~20% → 머리 공격 배율 증가
**예시 계산**:
```
[룬 적용 전]
기본 머리 배율: 1.2배
HeadAttackDamagePer: 0%
→ HitBoxRate = 1.2 + 0 = 1.2
[10103 공략 Lv.5 장착 후]
기본 머리 배율: 1.2배
HeadAttackDamagePer: 20% (룬 효과)
→ HitBoxRate = 1.2 + 0.20 = 1.4 (16.7% 추가 증가)
```
#### 5.4.3 저항 적용 단계 (섹션 1.2 [5] 참조)
룬은 **저항 수치**를 직접 증가시켜 받는 피해를 감소시킵니다:
```cpp
// WSDamageCalculation.cpp:543-613
// 공격 타입에 따라 적용되는 저항 결정
if (EAttackType == EWSAttackType::PhysicalSkill)
{
ResistancePer1 = PhysicalResistancePer; // 룬 10202가 영향
ResistancePer2 = ElementResistance;
}
else if (EAttackType == EWSAttackType::MagicalSkill)
{
ResistancePer1 = MagicalResistancePer; // 룬 10302가 영향
ResistancePer2 = ElementResistance;
}
```
**영향을 주는 룬**:
- **10202 방패**: PhysicalResistancePer +2~7% → 물리 피해 저항 증가
- **10302 수호**: MagicalResistancePer +2~7% → 마법 피해 저항 증가
**예시 계산**:
```
[룬 적용 전]
들어오는 물리 피해: 200
PhysicalResistancePer: 30%
→ 최종 피해 = 200 × (1 - 0.30) = 140
[10202 방패 Lv.5 장착 후]
들어오는 물리 피해: 200
PhysicalResistancePer: 37% (30% + 7% 룬 효과)
→ 최종 피해 = 200 × (1 - 0.37) = 126 (10% 추가 감소)
```
#### 5.4.4 최종 Damage 계산 단계 (섹션 1.2 [7] 참조)
룬은 **SkillPer 계산**에서 SkillDamagePer를 통해 영향을 줍니다:
```cpp
// WSDamageCalculation.cpp:543-613
if (EAttackType == EWSAttackType::PhysicalSkill)
{
BaseDamage = PhysicalDamage;
SkillPer = PhysicalSkillPer + SkillDamagePer; // 룬 20201이 영향
}
else if (EAttackType == EWSAttackType::MagicalSkill)
{
BaseDamage = MagicalDamage;
SkillPer = MagicalSkillPer + SkillDamagePer; // 룬 20201이 영향
}
```
**영향을 주는 룬**:
- **20201 파괴**: SkillDamagePer +6~10% → 모든 스킬 피해 증가
**예시 계산**:
```
[룬 적용 전]
BaseDamage: 288
SkillPer: 120% (PhysicalSkillPer만)
→ 스킬 피해 배율 = 288 × 1.20 = 345.6
[20201 파괴 Lv.5 장착 후]
BaseDamage: 288
SkillPer: 130% (PhysicalSkillPer 120% + SkillDamagePer 10%)
→ 스킬 피해 배율 = 288 × 1.30 = 374.4 (8.3% 추가 증가)
```
#### 5.4.5 몬스터 타입별 추가 피해 (섹션 2.3 참조)
룬은 **PassiveSet**에 몬스터 타입별 피해 증가 속성을 추가합니다:
**영향을 주는 룬**:
- **50201 학살**: NormalEnemyDamagePer +20~30%
- **50202 퇴치**: EliteEnemyDamagePer +16~20%
- **50203 격퇴**: BossEnemyDamagePer +11~15%
**적용 방식**:
이 룬들은 최종 Damage 계산 후 몬스터 타입에 따라 추가 곱셈이 적용되는 것으로 추정됩니다 (구체적인 코드 위치는 추가 확인 필요).
```
예상 공식:
최종 피해 = [기존 계산 피해] × (1 + [몬스터 타입별 피해 증가율])
```
#### 5.4.6 궁극기 게이지 충전 (섹션 1.4 참조)
룬은 **UltimateRecoveryPer**를 통해 궁극기 게이지 충전 속도에 영향을 줍니다:
**영향을 주는 룬**:
- **10101 충전**: UltimateRecoveryPer +15~30%
궁극기 게이지는 피해를 주거나 힐을 할 때 충전되며, 이 룬은 충전량을 백분율로 증가시킵니다.
#### 5.4.7 스킬 코스트 및 쿨타임 (섹션 2.3 참조)
룬은 **PassiveSet**의 스킬 관련 속성들을 수정합니다:
**영향을 주는 룬**:
- **20202 왜곡**: SkillCoolTimeReducePer +15~25% → 쿨타임 감소
- **20203 절약**: ManaCostPer -25~-50% → 마나 소모 감소
- **20302 영창**: CastingTimePer -15~-30% → 시전 시간 감소
**예시 계산 (쿨타임)**:
```
[룬 적용 전]
스킬 기본 쿨타임: 10초
SkillCoolTimeReducePer: 0%
→ 실제 쿨타임 = 10초
[20202 왜곡 Lv.5 장착 후]
스킬 기본 쿨타임: 10초
SkillCoolTimeReducePer: 25%
→ 실제 쿨타임 = 10 × (1 - 0.25) = 7.5초
```
### 5.5 룬 구현 메커니즘
#### 5.5.1 직접 속성 수정 방식
대부분의 룬은 `attributeModifies` 배열을 통해 PassiveSet 또는 CharacterSet 속성을 직접 수정합니다:
```json
{
"runeSet": "10201",
"level": 5,
"runeName": "분노",
"desc": "물리 피해 {Value0}% 증가",
"descValue": [10],
"attributeModifies": [
{
"attribute": {
"attributeName": "PhysicalDamagePer",
"attribute": "/Script/WorldStalker.PassiveSet:PhysicalDamagePer"
},
"value": 10
}
]
}
```
이 방식은 GAS(Gameplay Ability System)를 통해 자동으로 적용되며, 별도의 C++ 코드가 필요 없습니다.
#### 5.5.2 Ability 기반 방식
일부 룬은 조건부 효과나 복잡한 로직이 필요하여 Blueprint Ability를 사용합니다:
```json
{
"runeSet": "10102",
"level": 1,
"runeName": "진격",
"desc": "공격 적중 시 n초간 이동 속도 {Value0}% 증가",
"descValue": [8, 2],
"attributeModifies": [],
"ability": "/Game/Blueprints/Abilities/Rune/GA_Rune_10102.GA_Rune_10102_C"
}
```
이러한 룬들은 특정 이벤트(공격 적중, 몬스터 처치 등)에 반응하거나, 동적인 스택 시스템을 구현합니다.
**Ability 기반 룬 목록**:
- 10102 진격, 20101 저주, 20102 침식, 20103 활기
- 30101 공허, 30103 완벽, 30201 용사, 30202 투사
- 30301 신속, 30302 정밀, 30303 강인
- 40102 만전, 40201 면역, 40202 기습
- 50101 선물, 50102 누적, 50103 탐험
#### 5.5.3 룬 데이터 조회 시스템
**코드 위치**: `WSGameplayAbility.cpp:1525-1550`
```cpp
bool UWSGameplayAbility::GetRuneDataRowBySetID(FName RuneSetId, FRuneDataRow& OutDataRow)
{
// 캐시된 룬 데이터 확인
if (CachedRuneDataRow)
{
OutDataRow = *CachedRuneDataRow;
return true;
}
// DataTable에서 룬 데이터 검색
UWSDataAsset* WSData = UWSDataAsset::GetData(GetAvatarActorFromActorInfo());
FString DataContextString = FString(TEXT("UWSGameplayAbility::GetRuneDataRowBySetID"));
TArray<FRuneDataRow*> RuneRows;
WSData->Rune->GetAllRows(DataContextString, RuneRows);
// RuneSet ID와 현재 Ability 레벨이 일치하는 룬 검색
for (FRuneDataRow* r : RuneRows)
{
if (r->RuneSet == RuneSetId && r->Level == GetAbilityLevel())
{
CachedRuneDataRow = r;
OutDataRow = *CachedRuneDataRow;
return true;
}
}
return false;
}
```
이 함수는 Blueprint에서 룬 데이터를 조회할 때 사용되며, 캐싱을 통해 성능을 최적화합니다.
### 5.6 룬 데이터 테이블 구조
#### DT_RuneGroup DataTable 어셋
룬 그룹의 구조와 각 라인에 포함된 룬 목록을 정의합니다:
```json
{
"RowName": "1000001",
"Data": {
"name": "전투 그룹",
"type": "Battle",
"icon": "/Game/_UI/Icon_Rune/...",
"coreLine": ["10101", "10102", "10103"],
"sub1Line": ["10201", "10202"],
"sub2Line": ["10301", "10302"]
}
}
```
**그룹 목록**:
1. **1000001** - 전투 (Battle): Core 3개, Sub1 2개, Sub2 2개
2. **2000001** - 스킬 (Skill): Core 3개, Sub1 3개, Sub2 2개
3. **3000001** - 장비 (Equipment): Core 3개, Sub1 2개, Sub2 3개
4. **4000001** - 보조 (Assist): Core 2개, Sub1 2개, Sub2 2개
5. **5000001** - 모험 (Adventure): Core 3개, Sub1 2개, Sub2 4개
#### DT_Rune DataTable 어셋
각 룬의 레벨별 상세 데이터를 정의합니다:
```json
{
"RowName": "1020105",
"Data": {
"runeSet": "10201",
"level": 5,
"icon": "/Game/_UI/Icon_Rune/RuneIcon_Rage.RuneIcon_Rage",
"runeName": "분노",
"desc": "물리 피해 {Value0}% 증가",
"descValue": [10],
"attributeModifies": [
{
"attribute": {
"attributeName": "PhysicalDamagePer",
"attribute": "/Script/WorldStalker.PassiveSet:PhysicalDamagePer"
},
"value": 10
}
],
"ability": "None",
"unlockGold": 0,
"unlockSkillPoint": 20
}
}
```
**주요 필드**:
- `runeSet`: 룬 ID (5자리)
- `level`: 룬 레벨 (1~5)
- `runeName`: 룬 이름
- `desc`: 설명 (UI 표시용, {Value0}, {Value1} 플레이스홀더 사용)
- `descValue`: 설명에 대입할 수치 배열
- `attributeModifies`: 직접 수정할 속성 목록
- `ability`: Blueprint Ability 경로 (복잡한 효과용)
- `unlockSkillPoint`: 해당 레벨 해금에 필요한 스킬 포인트
### 5.7 룬 시스템 활용 전략
#### 공격력 극대화 빌드
**목표**: BaseDamage와 스킬 피해를 최대한 증가
**Main: 스킬 그룹**
- 20101 저주 (조건부 피해)
- 20201 파괴 (+10% 스킬 피해)
- 20301 명상 (+70% 마나 회복)
**Sub: 전투 그룹**
- 10201 분노 (+10% 물리 피해) 또는 10301 폭풍 (+10% 마법 피해)
- 10103 공략 (+20% 머리 공격)
**효과**: 스킬 피해 +10%, 물리/마법 피해 +10%, 머리 공격 +20%
#### 생존력 극대화 빌드
**Main: 전투 그룹**
- 10101 충전 (+30% 궁극기 회복)
- 10202 방패 (+7% 물리 저항)
- 10302 수호 (+7% 마법 저항)
**Sub: 보조 그룹**
- 40201 면역 (물약 사용 시 저항 +20%)
- 40301 효율 (물약 효과 +50%)
**효과**: 저항 대폭 증가, 물약 효율 극대화, 궁극기 빠른 충전
#### 스킬 연타 빌드
**Main: 스킬 그룹**
- 20201 파괴 (+10% 스킬 피해)
- 20202 왜곡 (+25% 쿨타임 감소)
- 20203 절약 (-50% 마나 소모)
**Sub: 스킬 그룹 Sub2**
- 20301 명상 (+70% 마나 회복)
- 20302 영창 (+30% 시전 속도)
**효과**: 쿨타임 -25%, 마나 소모 -50%, 마나 회복 +70%, 시전 속도 +30%
---
**룬 시스템 핵심 요약**:
1. 5개 그룹 × 3개 라인으로 구성된 38개 룬 세트
2. Main(3룬) + Sub(2룬)으로 총 5개 룬 장착
3. 직접 속성 수정 또는 Ability를 통한 조건부 효과
4. 전투 로직의 여러 단계에 직접적인 영향
5. BaseDamage, 저항, 스킬 코스트 등 핵심 수치 조정
---
## 6. 전투 관련 코드 목록
### 6.1 데미지 계산 시스템
#### WSDamageCalculation.cpp (1238라인)
**역할**: 모든 일반 공격 및 스킬 데미지 계산의 핵심 로직 실행
**주요 함수**:
- `Execute_Implementation` (라인 251-1238): 전체 11단계 계산 흐름 제어
- `DamageStatics()`: Attribute 캡처 정의
**주요 계산 단계별 코드 위치**:
1. **BaseDamage 계산**:
```cpp
// 라인 316-322: Level 배율 적용
PhysicalDamage = PhysicalDamage * Level;
MagicalDamage = MagicalDamage * Level;
// 라인 543-613: 공격 타입별 BaseDamage 결정
if (EAttackType == EWSAttackType::Normal)
BaseDamage = PhysicalDamage;
else if (EAttackType == EWSAttackType::PhysicalSkill)
BaseDamage = PhysicalDamage;
else if (EAttackType == EWSAttackType::MagicalSkill)
BaseDamage = MagicalDamage;
// 라인 620-685: 던전 룰 배율
switch (DungeonRule) {
case EDungeonRule::EnemyAtkUp: BaseDamage *= 1.4f; break;
// ...
}
```
2. **HitBox 판정** (라인 470-510):
```cpp
IsFrontAttack = UWSAbilityBlueprintLibrary::IsFrontAttack(EffectCauser, Target, bUseOwnerRotation);
if (HitResult->BoneName == FName(TEXT("b_Head")))
{
IsHeadShot = true;
HitBoxRate = 1.2f + HeadAttackDamagePer * 0.01f;
HitBoxRate -= 0.5f * HeadShotDamReducePer * 0.01f;
}
```
3. **치명타 판정** (라인 512-527):
```cpp
if (bUseCritical && FMath::FRandRange(0.0f, 100.0f) < CriticalPer)
{
isCritical = true;
CriticalDamageRate = (CriticalDamagePer * 0.01f) + (FMath::Rand() * CriticalDamageRange);
}
```
4. **저항 및 최종 피해** (라인 706-718):
```cpp
ResistancePer1 = FMath::Min(ResistancePer1, 75.0f);
ResistancePer2 = FMath::Min(ResistancePer2, 75.0f);
Damage = Floor(BaseDamage * HitBoxRate * (SkillPer * 0.01) *
((1 - ResistancePer1 * 0.01) * (1 - ResistancePer2 * 0.01) * (1 - DamageReductionPer * 0.01)) *
CriticalDamageRate * (1 - TakeDamageReductionPer * 0.01) * (1 + TakeDamageIncreasePer * 0.01));
```
5. **Shield/Armor/HP 적용** (라인 883-1047):
```cpp
// Shield 먼저 소모
ShieldDamage = Clamp(DamageNoResist, 0, Shield);
if (Shield > 0) {
Damage = Clamp(Damage - ShieldDamage, 0, Damage);
Shield -= ShieldDamage;
}
// Armor Gating
if (Armor / ArmorMax > 0.5) {
DamageGating = (Armor - Damage) - (ArmorMax * 0.5);
if (DamageGating < 0) Damage += DamageGating;
}
```
**참조 섹션**: 1.2 일반 공격/스킬 데미지 계산 흐름
---
#### WSHealCalculation.cpp (126라인)
**역할**: 힐 스킬의 회복량 계산
**주요 함수**:
- `Execute_Implementation` (라인 49-125): 힐 계산 및 적용
**힐 계산 공식** (라인 95-98):
```cpp
float HealMagnitude = InComingHeal * Level;
// 힐 = 기본 힐량 + (마법공격력 × 스킬 계수) × (인트배율)
HealMagnitude = HealMagnitude + (MagicalDamage * (1.0f + (SkillDamagePer * 0.01f))) * (MagicalSkillPer * 0.01f);
```
**과치유 방지** (라인 106-108):
```cpp
float TargetMaxHP = TargetASC->GetNumericAttribute(UCharacterSet::GetHPMaxAttribute());
float TargetHP = TargetASC->GetNumericAttribute(UCharacterSet::GetHPAttribute());
float HealAmount = FMath::Min(HealMagnitude, TargetMaxHP - TargetHP);
```
**힐 무효 처리** (라인 110-113):
```cpp
if (TargetASC->HasMatchingGameplayTag(FGameplayTag::RequestGameplayTag("Effect.IgnoreHeal")))
{
HealAmount = 0.0f;
}
```
**궁극기 게이지 충전** (라인 118-123):
```cpp
if (!SourceASC->HasMatchingGameplayTag(FGameplayTag::RequestGameplayTag("Ability.Ultimate")))
{
InstigatorCharacter->CharacterSet->SetUltimateCurrentValue(
FMath::Min(HealAmount + UltimateCurrentvalue, UltimateMaxValue));
}
```
**참조 섹션**: 1.4 힐 계산
---
### 6.2 속성 세트 (Attribute Sets)
#### WSAttributeSet.h
**역할**: 모든 Attribute Set의 베이스 클래스
**주요 기능**:
- Gameplay Attribute 시스템의 기본 구조 제공
- Replication 설정
- Attribute 변경 감지 및 클램핑
---
#### PrimarySet.h
**역할**: 1차 스탯 (Str, Dex, Int, Con, Wis) 정의
**속성**:
```cpp
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Str)
float Str = 0; // 힘
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Dex)
float Dex = 0; // 민첩
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Int)
float Int = 0; // 지능
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Con)
float Con = 0; // 체질
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Wis)
float Wis = 0; // 지혜
```
**특징**:
- 총합 75 제한
- 커브 테이블을 통해 2차 스탯 피해율로 변환
- 장비, 패시브 스킬로 추가 증가 가능
**참조 섹션**: 2.1 1차 스탯
---
#### CharacterSet.h
**역할**: 2차 스탯 (HP, Damage, Defense, Resistance 등) 정의
**주요 속성 그룹**:
1. **기본 스탯**: HP, MP, Stamina, Shield
2. **피해**: PhysicalDamage, MagicalDamage, 각종 피해율
3. **방어**: Defense, Armor, 저항
4. **특수**: Breakdown, Ultimate, Critical
**초기화** (CharacterSet.cpp:8-82):
```cpp
void UCharacterSet::InitData(FCharacterStatData Data, UPrimarySet* PrimarySet, UPassiveSet* PassiveSet, bool HasAuthority)
{
SetPhysicalDamage(Data.PhysicalDamage);
SetMagicalDamage(Data.MagicalDamage);
SetDefense(Data.Defense);
// ...
}
```
**참조 섹션**: 2.2 2차 스탯
---
#### PassiveSet.h (490라인)
**역할**: 패시브 스탯 (백분율 수정자) 정의
**속성 구성**:
- **공통 패시브** (라인 125-260): 36개 속성
- 피해 증가율 (PhysicalDamagePer, MagicalDamagePer 등)
- 방어/속도/HP/MP 증가율
- 스킬 코스트/쿨다운 감소율
- 인터랙션 시간 조정
- **캐릭터별 전용 퍽** (라인 263-461):
- Hilda: 7개 전용 퍽
- Urud: 6개 전용 퍽
- Nave: 10개 전용 퍽
- Baran: 8개 전용 퍽
- Rio: 8개 전용 퍽
- Clad: 5개 전용 퍽
- **범용 퍽 슬롯** (라인 466-488): Perk1~Perk8
**적용 방식**:
```cpp
// WSCharacterPlayer.cpp:4018-4022
float PhysicalDamagePer = AbilitySystemComponent->GetNumericAttribute(
UPassiveSet::GetPhysicalDamagePerAttribute()) * 0.01f;
AttrValueMap[UCharacterSet::GetPhysicalDamageAttribute()] +=
AttrValueMap[UCharacterSet::GetPhysicalDamageAttribute()] * PhysicalDamagePer;
```
**참조 섹션**: 2.3 패시브 스탯
---
#### EnemySet.h
**역할**: 몬스터 전용 스탯 정의
**주요 속성**:
```cpp
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CombinationArmor)
float CombinationArmor = 0; // 몬스터 전용 콤비네이션 아머
```
**특징**:
- 몬스터에게만 적용되는 특수 속성
- CombinationArmor: 다중 부위 아머 시스템
---
### 6.3 캐릭터 시스템
#### WSCharacterBase.cpp/h
**역할**: 플레이어와 적 캐릭터의 공통 베이스 클래스
**주요 기능**:
1. **Ability System 초기화**:
```cpp
void AWSCharacterBase::InitializeAbilitySystem()
{
AbilitySystemComponent->InitAbilityActorInfo(this, this);
PrimarySet->InitData(*StatDataRow);
CharacterSet->InitData(*StatDataRow, PrimarySet, PassiveSet, HasAuthority());
}
```
2. **반죽음 판정** (WSCharacterBase.h:178-180):
```cpp
bool CanHalfDie() const
{
// 파티원이 있고 생존한 파티원이 있을 때만 반죽음 가능
return HasPartyMembers() && HasAlivePartyMembers();
}
```
3. **Hit Reaction 처리**:
- 피격 모션 재생
- 넉백/스턴 처리
- Breakdown 게이지 증가
**참조 섹션**: 4.3 반죽음
---
#### WSCharacterPlayer.cpp/h
**역할**: 플레이어 캐릭터 전용 로직
**주요 기능**:
1. **1차 스탯 → 2차 스탯 변환** (라인 3214-3245):
```cpp
void AWSCharacterPlayer::UpdatePrimaryStats()
{
FRealCurve* NormalDamagePerCurve = WSData->PrimaryStat->FindSimpleCurve(FName(TEXT("NormalDamagePer")), DataContextString);
CharacterSet->SetNormalDamagePer(NormalDamagePerCurve->Eval(PrimarySet->GetStr()));
FRealCurve* PhysicalSkillPerCurve = WSData->PrimaryStat->FindSimpleCurve(FName(TEXT("PhysicalSkillPer")), DataContextString);
CharacterSet->SetPhysicalSkillPer(PhysicalSkillPerCurve->Eval(PrimarySet->GetStr()));
FRealCurve* MagicalSkillPerCurve = WSData->PrimaryStat->FindSimpleCurve(FName(TEXT("MagicalSkillPer")), DataContextString);
CharacterSet->SetMagicalSkillPer(MagicalSkillPerCurve->Eval(PrimarySet->GetInt()));
}
```
2. **장비 효과 적용** (라인 3566-3860):
```cpp
void AWSCharacterPlayer::GiveEquip(FEquipItemData* EquipItem, int CacheIndex)
{
// 장비 랜덤 옵션 적용
AttrValueMap.Add(UCharacterSet::GetPhysicalDamageAttribute(),
FItemHelper::CalculateOption(EquipItem, EItemOption::PhysicalDamageInc));
// 패시브 스탯 백분율 적용
float PhysicalDamagePer = AbilitySystemComponent->GetNumericAttribute(
UPassiveSet::GetPhysicalDamagePerAttribute()) * 0.01f;
AttrValueMap[UCharacterSet::GetPhysicalDamageAttribute()] +=
AttrValueMap[UCharacterSet::GetPhysicalDamageAttribute()] * PhysicalDamagePer;
}
```
3. **스킬/패시브 관리**:
- 스킬 슬롯 관리
- 패시브 스킬 활성화
- 퍽 시스템 적용
**참조 섹션**: 1.1 BaseDamage 계산 과정
---
#### WSCharacterEnemy.cpp/h
**역할**: 적 캐릭터 전용 로직
**주요 기능**:
- AI 연동
- Breakdown 시스템
- 몬스터 등급별 스탯 조정
- CombinationArmor 처리
---
### 6.4 스킬 데이터 구조
#### SkillDataRow.h
**역할**: 스킬 데이터 테이블 구조 정의
**주요 열거형**:
1. **공격 타입** (라인 13-21):
```cpp
UENUM(BlueprintType)
enum class EWSAttackType : uint8
{
Normal = 0, // 일반 공격
PhysicalSkill = 1, // 물리 스킬
MagicalSkill = 2, // 마법 스킬
FixedSkill = 3, // 고정 스킬 (저항 무시)
None = 4
};
```
2. **원소 타입** (라인 24-33):
```cpp
UENUM(BlueprintType)
enum class EWSElementType : uint8
{
None = 0,
Fire = 1, // 화염
Poison = 2, // 독
Water = 3, // 물
Lightning = 4, // 번개
Holy = 5, // 빛
Dark = 6 // 암흑
};
```
**스킬 데이터 구조**:
```cpp
USTRUCT(BlueprintType)
struct FSkillDataRow : public FTableRowBase
{
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float BaseDamage; // 기본 피해량
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
EWSAttackType AttackType; // 공격 타입
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
EWSElementType ElementType; // 원소 타입
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float ManaCost; // 마나 소비
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float CooldownTime; // 쿨다운 시간
// ... 기타 스킬 속성
};
```
**참조 섹션**: 3.1 공격 타입, 3.2 원소 타입
---
### 6.5 발사체 시스템
#### WSProjectileBase.cpp/h
**역할**: 화살, 마법 투사체 등 원거리 공격 구현
**주요 기능**:
1. 투사체 물리 시뮬레이션
2. 충돌 감지 및 히트 판정
3. 관통, 폭발 등 특수 효과
4. RangedType 설정
**히트 처리**:
```cpp
void AWSProjectileBase::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, FVector NormalImpulse,
const FHitResult& Hit)
{
// RangedType = true 설정
// GameplayEffect 적용 (WSDamageCalculation 호출)
// RangedResistancePer 저항 적용됨
}
```
**참조 섹션**: 3.2 원거리 타입
---
### 6.6 기타 데이터 구조
#### CharacterStatDataRow.h
**역할**: 캐릭터 기본 스탯 DataTable 구조
**주요 필드** (라인 63-198):
```cpp
USTRUCT(BlueprintType)
struct FCharacterStatData : public FTableRowBase
{
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float Str = 0; // 1차 스탯
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float PhysicalDamage = 0; // 캐릭터 기본 공격력
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float MagicalDamage = 0; // 캐릭터 기본 마법 공격력
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float Defense = 0; // 캐릭터 기본 방어력
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float BreakdownMax = -1.0f; // 브레이크다운 최대치
// ... 기타 기본 스탯
};
```
**사용 위치**:
- `WSCharacterPlayer::InitializeAbilitySystem` (라인 1059)
- `PrimarySet::InitData`
- `CharacterSet::InitData`
**참조 섹션**: 1.1 BaseDamage 계산 과정 (1단계)
---
#### DataTable.json
**역할**: 언리얼 에디터의 DataTable 어셋을 JSON 형식으로 익스포트한 파일
> **참고**: 이 파일은 "Asset Export to JSON" 에디터 확장 기능을 통해 생성된 결과물입니다.
> 언리얼 엔진의 DataTable 어셋(DT_Rune, DT_RuneGroup 등)을 LLM이 분석할 수 있도록 텍스트 기반 JSON 형식으로 변환한 것입니다.
**룬 시스템 관련 DataTable 어셋**:
- **DT_RuneGroup**: 5개 룬 그룹 구조 정의
- Core Line, Sub 1Line, Sub 2Line 구성
- 각 그룹별 선택 가능 룬 목록
- **DT_Rune**: 38개 룬 세트의 레벨별 데이터
- 룬 ID (runeSet), 레벨 (1~5)
- 효과 설명 (desc, descValue)
- 직접 속성 수정 (attributeModifies) 또는 Ability 참조
- 해금 조건 (unlockSkillPoint)
```json
{
"runeSet": "10201",
"level": 5,
"runeName": "분노",
"desc": "물리 피해 {Value0}% 증가",
"descValue": [10],
"attributeModifies": [
{
"attribute": {
"attributeName": "PhysicalDamagePer",
"attribute": "/Script/WorldStalker.PassiveSet:PhysicalDamagePer"
},
"value": 10
}
]
}
```
**참조 섹션**: 5.6 룬 데이터 테이블 구조
---
#### WSGameplayAbility.h/cpp
**역할**: Gameplay Ability 베이스 클래스, **룬 데이터 조회 기능 포함**
**룬 관련 함수** (WSGameplayAbility.h:209, 268):
```cpp
// 룬 데이터 조회 함수
UFUNCTION(BlueprintCallable, Category = "WorldStalker")
bool GetRuneDataRowBySetID(FName RuneSetId, FRuneDataRow& OutDataRow);
// 룬 데이터 캐시
FRuneDataRow* CachedRuneDataRow;
```
**구현** (WSGameplayAbility.cpp:1525-1550):
- RuneSet ID와 Ability 레벨로 룬 데이터 검색
- 캐싱을 통한 성능 최적화
- Blueprint에서 룬 효과 적용 시 사용
**참조 섹션**: 5.5.3 룬 데이터 조회 시스템