2025-10-27 17:04:37 +09:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
"""
|
|
|
|
|
스토커 데이터 분석 v2 - 설정 파일
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
# 프로젝트 루트
|
|
|
|
|
PROJECT_ROOT = Path(__file__).parent.parent.parent
|
|
|
|
|
|
|
|
|
|
# 원본 데이터 경로
|
|
|
|
|
DATA_DIR = PROJECT_ROOT / "원본데이터"
|
|
|
|
|
DATATABLE_JSON = DATA_DIR / "DataTable.json"
|
|
|
|
|
BLUEPRINT_JSON = DATA_DIR / "Blueprint.json"
|
|
|
|
|
ANIMMONTAGE_JSON = DATA_DIR / "AnimMontage.json"
|
|
|
|
|
CURVETABLE_JSON = DATA_DIR / "CurveTable.json"
|
|
|
|
|
|
2025-11-05 11:09:16 +09:00
|
|
|
# 출력 디렉토리 (Git 버전관리용 고정 경로)
|
2025-10-27 17:04:37 +09:00
|
|
|
def get_output_dir(create_new: bool = False) -> Path:
|
|
|
|
|
"""
|
|
|
|
|
출력 디렉토리 가져오기
|
2025-11-05 11:09:16 +09:00
|
|
|
- Git으로 버전관리하므로 타임스탬프 폴더 생성하지 않음
|
|
|
|
|
- 항상 분석결과/ 직접 사용
|
2025-10-27 17:04:37 +09:00
|
|
|
"""
|
|
|
|
|
result_base = PROJECT_ROOT / "분석결과"
|
|
|
|
|
result_base.mkdir(parents=True, exist_ok=True)
|
2025-11-05 11:09:16 +09:00
|
|
|
return result_base
|
2025-10-27 17:04:37 +09:00
|
|
|
|
|
|
|
|
OUTPUT_DIR = get_output_dir()
|
|
|
|
|
|
|
|
|
|
# 스토커 목록 (순서: 기존 문서 기준)
|
|
|
|
|
STALKERS = [
|
|
|
|
|
'hilda', # 1. 힐다 - 방어형 전사
|
|
|
|
|
'urud', # 2. 우르드 - 원거리 딜러
|
|
|
|
|
'nave', # 3. 네이브 - 마법사
|
|
|
|
|
'baran', # 4. 바란 - 파워 전사
|
|
|
|
|
'rio', # 5. 리오 - 암살자
|
|
|
|
|
'clad', # 6. 클라드 - 성직자
|
|
|
|
|
'rene', # 7. 레네 - 소환사
|
|
|
|
|
'sinobu', # 8. 시노부 - 닌자
|
|
|
|
|
'lian', # 9. 리안 - 레인저
|
|
|
|
|
'cazimord' # 10. 카지모르드 - 평타 중심 전사
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# 스토커 정보 (영문 이름, 한글 이름, 직업)
|
|
|
|
|
STALKER_INFO = {
|
|
|
|
|
'hilda': {'english': 'Hilda', 'name': '힐다', 'job': '전사', 'role': '탱커'},
|
|
|
|
|
'urud': {'english': 'Urud', 'name': '우르드', 'job': '원거리', 'role': '원거리 딜러'},
|
|
|
|
|
'nave': {'english': 'Nave', 'name': '네이브', 'job': '마법사', 'role': '광역 마법 딜러'},
|
|
|
|
|
'baran': {'english': 'Baran', 'name': '바란', 'job': '전사', 'role': '고화력 전사'},
|
|
|
|
|
'rio': {'english': 'Rio', 'name': '리오', 'job': '암살자', 'role': '빠른 근접 암살자'},
|
|
|
|
|
'clad': {'english': 'Clad', 'name': '클라드', 'job': '성직자', 'role': '서포터/힐러'},
|
|
|
|
|
'rene': {'english': 'Rene', 'name': '레네', 'job': '소환사', 'role': '소환사/마법 딜러'},
|
|
|
|
|
'sinobu': {'english': 'Sinobu', 'name': '시노부', 'job': '닌자', 'role': '기동형 암살자'},
|
|
|
|
|
'lian': {'english': 'Lian', 'name': '리안', 'job': '레인저', 'role': '정밀 원거리 딜러'},
|
|
|
|
|
'cazimord': {'english': 'Cazimord', 'name': '카지모르드', 'job': '전사', 'role': '고숙련도 하이브리드 전사'}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 분석 기준 (기존 문서 기준)
|
|
|
|
|
ANALYSIS_BASELINE = {
|
|
|
|
|
'level': 20,
|
|
|
|
|
'gear_score': 400,
|
|
|
|
|
'play_style': '최적 플레이',
|
|
|
|
|
'rune_effect': {
|
|
|
|
|
'cooltime_reduction': 0.25, # 왜곡 룬 -25% 쿨타임
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# DoT 스킬 목록
|
|
|
|
|
DOT_SKILLS = {
|
|
|
|
|
'SK110204': {'stalker': 'urud', 'name': '독성 화살', 'dot_type': 'Poison'},
|
|
|
|
|
'SK160203': {'stalker': 'rene', 'name': '독기 화살', 'dot_type': 'Bleed'},
|
|
|
|
|
'SK170201': {'stalker': 'cazimord', 'name': '작열', 'dot_type': 'Burn'}, # 수정: SK170203 -> SK170201
|
|
|
|
|
'SK160202': {'stalker': 'rene', 'name': '정령 소환: 화염', 'dot_type': 'Burn'} # Ifrit 화상
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# DoT 피해 상세 정보
|
|
|
|
|
DOT_DAMAGE = {
|
|
|
|
|
'Poison': {
|
|
|
|
|
'rate': 0.20, # 대상 MaxHP의 20%
|
|
|
|
|
'duration': 5, # 5초간
|
|
|
|
|
'description': '대상 MaxHP의 20% (5초간)'
|
|
|
|
|
},
|
|
|
|
|
'Burn': {
|
|
|
|
|
'rate': 0.10, # 대상 MaxHP의 10%
|
|
|
|
|
'duration': 3, # 3초간
|
|
|
|
|
'description': '대상 MaxHP의 10% (3초간)'
|
|
|
|
|
},
|
|
|
|
|
'Bleed': {
|
|
|
|
|
'damage': 20, # 고정 20 피해
|
|
|
|
|
'duration': 5, # 5초간
|
|
|
|
|
'description': '고정 20 피해 (5초간)'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 소환수 스킬 (특수 DPS 계산 필요)
|
|
|
|
|
SUMMON_SKILLS = {
|
|
|
|
|
'SK160202': {
|
|
|
|
|
'stalker': 'rene',
|
|
|
|
|
'name': '정령 소환: 화염',
|
|
|
|
|
'summon': 'Ifrit',
|
|
|
|
|
'type': 'npc' # DT_NPCAbility 사용
|
|
|
|
|
},
|
|
|
|
|
'SK160206': {
|
|
|
|
|
'stalker': 'rene',
|
|
|
|
|
'name': '정령 소환: 냉기',
|
|
|
|
|
'summon': 'Shiva',
|
|
|
|
|
'type': 'special', # DT_NPCAbility 사용 안 함
|
|
|
|
|
'montage': 'AM_Sum_Elemental_Ice_Attack_N01', # 직접 지정
|
|
|
|
|
'attack_interval_bonus': 1.0 # 공격 주기에 추가되는 시간(초)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 유틸리티 스킬 (DPS 제외 - 확실한 것만 명시)
|
|
|
|
|
# 공격 노티파이가 없는 스킬들
|
|
|
|
|
UTILITY_SKILLS = {
|
|
|
|
|
'SK100204': 'hilda - 도발',
|
|
|
|
|
'SK110201': 'urud - 덫 설치',
|
|
|
|
|
'SK110207': 'urud - Reload', # 재장전
|
|
|
|
|
'SK120101': 'nave - 마력 충전',
|
|
|
|
|
'SK130101': 'baran - 무기 막기',
|
|
|
|
|
'SK150206': 'clad - 치유',
|
|
|
|
|
'SK150202': 'clad - 신성한 빛 (DOT 제거)',
|
2025-10-28 12:34:12 +09:00
|
|
|
'SK150301': 'clad - 마석 황금 (보호막)', # 궁극기 - 보호막 스킬
|
|
|
|
|
'SK160301': 'rene - 마석 붉은 축제 (흡혈 버프)', # 궁극기 - 흡혈 버프
|
|
|
|
|
'SK190301': 'lian - 마석 폭우 (쿨타임 감소)', # 궁극기 - 쿨타임 감소 버프
|
2025-10-27 17:04:37 +09:00
|
|
|
'SK180205': 'sinobu - 바꿔치기 (피격 시 효과)',
|
|
|
|
|
'SK180206': 'sinobu - 인술 칠흑안개',
|
|
|
|
|
'SK190209': 'lian - 재장전', # 재장전
|
|
|
|
|
'SK100101': 'hilda - 방패 들기',
|
|
|
|
|
'SK150101': 'clad - 방패 방어',
|
|
|
|
|
'SK170101': 'cazimord - Parrying',
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 공격 스킬로 확정된 스킬 (노티파이 확인 완료)
|
|
|
|
|
# 주의: 아래 스킬들은 UTILITY_SKILLS에서 제외됨
|
|
|
|
|
CONFIRMED_ATTACK_SKILLS = {
|
|
|
|
|
'SK130301': 'baran - 일격분쇄 (Event.SkillActivate)',
|
|
|
|
|
'SK150201': 'clad - 다시 흙으로 (Event.SkillActivate)',
|
|
|
|
|
'SK190201': 'lian - 연화 (Event.SpawnProjectile)',
|
|
|
|
|
'SK190101': 'lian - 정조준 (Projectile Shot)', # UTILITY에서 제거됨
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 공격 스킬 판별 기준 (우선순위)
|
|
|
|
|
#
|
|
|
|
|
# 우선순위 1: AnimNotify의 NotifyName에 다음 키워드 포함 (부분 매칭)
|
|
|
|
|
# - 실질적으로 데미지가 발생하는 시점을 나타내는 노티파이
|
|
|
|
|
ATTACK_NOTIFY_KEYWORDS = [
|
|
|
|
|
'AttackWithEquip', # 무기 공격 (근접)
|
|
|
|
|
'Projectile', # 투사체 발사 (AN_Projectile_C, AN_Trigger_Projectile_Shot_C 등)
|
|
|
|
|
'SkillActive', # 스킬 활성화 (AN_Trigger_Skill_Active_C)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# 우선순위 2: AN_SimpleSendEvent 노티파이의 Event Tag
|
|
|
|
|
# - 1순위에 해당되지 않을 때 2순위로 확인
|
|
|
|
|
ATTACK_EVENT_TAGS = [
|
|
|
|
|
'Event.SkillActivate', # 스킬 활성화 (바란, 클라드 등)
|
|
|
|
|
'Event.SpawnProjectile', # 투사체 생성 (리옌 연화 등)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# BaseDamage 계산식 (기존 분석 기준)
|
|
|
|
|
BASE_DAMAGE_FORMULA = {
|
|
|
|
|
'physical_str': lambda stats: (stats['str'] + 80) * 1.20,
|
|
|
|
|
'physical_dex': lambda stats: (stats['dex'] + 80) * 1.20,
|
|
|
|
|
'magical': lambda stats: (stats['int'] + 80) * 1.10,
|
2025-10-28 12:34:12 +09:00
|
|
|
'support': lambda stats: (stats['str'] + 80) * 1.00 # Clad uses STR, not WIS
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-05 11:09:16 +09:00
|
|
|
# 특수 궁극기 처리
|
2025-10-28 12:34:12 +09:00
|
|
|
SPECIAL_ULTIMATE_HANDLING = {
|
|
|
|
|
'SK130301': { # 바란 - 일격분쇄
|
|
|
|
|
'stalker': 'baran',
|
|
|
|
|
'use_an_simplesendevent_time': True, # AN_SimpleSendEvent 시간 사용
|
|
|
|
|
'event_tag': 'Ability.Attack.Ready',
|
|
|
|
|
'description': 'AN_SimpleSendEvent 시점(1.29초)이 실제 발동 시간, 10초는 최대 홀딩 시간'
|
|
|
|
|
}
|
2025-10-27 17:04:37 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 검증 기준
|
|
|
|
|
VALIDATION_RULES = {
|
|
|
|
|
'stat_total': 75, # 모든 스토커 스탯 합계
|
|
|
|
|
'hp': 100,
|
|
|
|
|
'mp': 50,
|
|
|
|
|
'mana_regen': 0.2,
|
|
|
|
|
'skill_damage_rate_min': 0.0,
|
|
|
|
|
'cooltime_min': 0.0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 시퀀스 길이 계산 규칙
|
|
|
|
|
SEQUENCE_CALCULATION_RULES = {
|
|
|
|
|
# 합산에서 제외할 몽타주 키워드 (대소문자 구분 없음)
|
|
|
|
|
'exclude_keywords': ['Ready', 'Equipment'],
|
|
|
|
|
|
|
|
|
|
# 평균값으로 계산할 스킬 (몽타주를 번갈아 사용)
|
|
|
|
|
'average_skills': ['SK160101'], # 레네 - 할퀴기
|
|
|
|
|
|
|
|
|
|
# 특정 몽타주를 제외할 스킬 (스킬ID: [제외할 몽타주 이름들])
|
|
|
|
|
'exclude_montages': {
|
|
|
|
|
'SK170201': ['AM_PC_Cazimord_B_Skill_Flash'], # 카지모르드 - 섬광 (첫 번째 몽타주 제외)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
# 인덱스로 제외할 몽타주 (스킬ID: [제외할 인덱스들, 0-based])
|
|
|
|
|
'exclude_montage_indices': {
|
|
|
|
|
'SK190205': [1], # 리옌 - 비연사 (두 번째 중복 몽타주 제외)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
# 몽타주 태그 표시
|
|
|
|
|
'montage_tags': {
|
|
|
|
|
'Ready': '[준비]',
|
|
|
|
|
'Equipment': '[장비]'
|
|
|
|
|
}
|
|
|
|
|
}
|