#!/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" # 출력 디렉토리 (타임스탬프 자동 생성) def get_output_dir(create_new: bool = False) -> Path: """ 출력 디렉토리 가져오기 - create_new=True: 새 타임스탬프 디렉토리 생성 - create_new=False: 가장 최근 디렉토리 사용 (없으면 생성) """ result_base = PROJECT_ROOT / "분석결과" result_base.mkdir(parents=True, exist_ok=True) if create_new: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") return result_base / f"{timestamp}_v2" # 기존 v2 디렉토리 중 가장 최근 것 찾기 (수정 시간 기준) v2_dirs = [d for d in result_base.iterdir() if d.is_dir() and d.name.endswith('_v2')] if v2_dirs: # 수정 시간 기준으로 정렬 v2_dirs_sorted = sorted(v2_dirs, key=lambda d: d.stat().st_mtime) return v2_dirs_sorted[-1] # 가장 최근 디렉토리 # 없으면 새로 생성 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") return result_base / f"{timestamp}_v2" 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 제거)', 'SK150301': 'clad - 마석 황금 (보호막)', # 궁극기 - 보호막 스킬 'SK160301': 'rene - 마석 붉은 축제 (흡혈 버프)', # 궁극기 - 흡혈 버프 'SK190301': 'lian - 마석 폭우 (쿨타임 감소)', # 궁극기 - 쿨타임 감소 버프 '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, 'support': lambda stats: (stats['str'] + 80) * 1.00 # Clad uses STR, not WIS } # 콤보 캔슬 시스템 (v2.1) # ANS_DisableBlockingState_C 노티파이로 조기 캔슬 가능 COMBO_CANCEL_STALKERS = { 'hilda': { 'weapons': ['weaponShield'], # 방패+무기 'patterns': ['AM_PC_Hilda_B_Attack_W01_'], # 평타 패턴 'time_reduction': 0.19, # 19% 시간 단축 'description': '3타 콤보 캔슬 (4.57s → 3.69s)' }, 'baran': { 'weapons': ['twoHandWeapon'], # 양손 무기 'patterns': ['AM_PC_Baran_B_Attack_W01_'], 'time_reduction': 0.19, # 19% 시간 단축 'description': '평타 콤보 캔슬 (5.53s → 4.48s)' }, 'clad': { 'weapons': ['oneHandWeapon'], # 한손 무기 (mace) 'patterns': ['AM_PC_Clad_Base_Attack_Mace'], 'time_reduction': 0.56, # 56% 시간 단축 (극적!) 'description': '평타 콤보 캔슬 (4.17s → 1.84s)' } } # 특수 궁극기 처리 (v2.1) SPECIAL_ULTIMATE_HANDLING = { 'SK130301': { # 바란 - 일격분쇄 'stalker': 'baran', 'use_an_simplesendevent_time': True, # AN_SimpleSendEvent 시간 사용 'event_tag': 'Ability.Attack.Ready', 'description': 'AN_SimpleSendEvent 시점(1.29초)이 실제 발동 시간, 10초는 최대 홀딩 시간' } } # 검증 기준 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': '[장비]' } }