초기 커밋: DS-전투시스템 종합분석 저장소
This commit is contained in:
107
분석도구/analyze_character_stats.py
Normal file
107
분석도구/analyze_character_stats.py
Normal file
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
캐릭터 스탯 분석 스크립트
|
||||
|
||||
DT_CharacterStat 테이블에서 스토커들의 기본 스탯을 추출하고 비교 분석합니다.
|
||||
|
||||
사용법:
|
||||
python analyze_character_stats.py <DataTable.json 경로>
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def find_character_stat_table(datatables):
|
||||
"""DT_CharacterStat 테이블 찾기"""
|
||||
for dt in datatables:
|
||||
if dt.get('AssetName') == 'DT_CharacterStat':
|
||||
return dt
|
||||
return None
|
||||
|
||||
|
||||
def analyze_stats(json_path):
|
||||
"""캐릭터 스탯 분석"""
|
||||
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
datatables = json.load(f)
|
||||
|
||||
char_stat_table = find_character_stat_table(datatables)
|
||||
|
||||
if not char_stat_table:
|
||||
print("오류: DT_CharacterStat 테이블을 찾을 수 없습니다.")
|
||||
return
|
||||
|
||||
stalkers = []
|
||||
|
||||
for row in char_stat_table.get('Rows', []):
|
||||
data = row['Data']
|
||||
stalker_info = {
|
||||
'id': row['RowName'],
|
||||
'name': data.get('name', ''),
|
||||
'job': data.get('jobName', ''),
|
||||
'str': data.get('str', 0),
|
||||
'dex': data.get('dex', 0),
|
||||
'int': data.get('int', 0),
|
||||
'con': data.get('con', 0),
|
||||
'wis': data.get('wis', 0),
|
||||
'hp': data.get('hP', 0),
|
||||
'mp': data.get('mP', 0)
|
||||
}
|
||||
stalkers.append(stalker_info)
|
||||
|
||||
return stalkers
|
||||
|
||||
|
||||
def print_stat_table(stalkers):
|
||||
"""스탯 테이블 출력"""
|
||||
print("\n스토커별 기본 스탯")
|
||||
print("=" * 100)
|
||||
print(f"{'이름':<10} {'직업':<10} {'STR':>5} {'DEX':>5} {'INT':>5} {'CON':>5} {'WIS':>5} {'HP':>5} {'MP':>5}")
|
||||
print("-" * 100)
|
||||
|
||||
for s in stalkers:
|
||||
print(f"{s['name']:<10} {s['job']:<10} {s['str']:>5} {s['dex']:>5} {s['int']:>5} {s['con']:>5} {s['wis']:>5} {s['hp']:>5} {s['mp']:>5}")
|
||||
|
||||
|
||||
def print_stat_rankings(stalkers):
|
||||
"""스탯별 랭킹 출력"""
|
||||
print("\n\n스탯별 랭킹")
|
||||
print("=" * 100)
|
||||
|
||||
stats = ['str', 'dex', 'int', 'con', 'wis']
|
||||
stat_names = {'str': 'STR', 'dex': 'DEX', 'int': 'INT', 'con': 'CON', 'wis': 'WIS'}
|
||||
|
||||
for stat in stats:
|
||||
sorted_stalkers = sorted(stalkers, key=lambda x: x[stat], reverse=True)
|
||||
top3 = sorted_stalkers[:3]
|
||||
|
||||
print(f"\n{stat_names[stat]} 순위:")
|
||||
for i, s in enumerate(top3, 1):
|
||||
print(f" {i}위: {s['name']} ({s[stat]})")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("사용법: python analyze_character_stats.py <DataTable.json 경로>")
|
||||
sys.exit(1)
|
||||
|
||||
json_path = Path(sys.argv[1])
|
||||
|
||||
if not json_path.exists():
|
||||
print(f"오류: 파일을 찾을 수 없습니다: {json_path}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"분석 중: {json_path}")
|
||||
|
||||
stalkers = analyze_stats(json_path)
|
||||
|
||||
if stalkers:
|
||||
print(f"\n총 {len(stalkers)}명의 스토커 발견")
|
||||
print_stat_table(stalkers)
|
||||
print_stat_rankings(stalkers)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
115
분석도구/extract_activation_order_groups.py
Normal file
115
분석도구/extract_activation_order_groups.py
Normal file
@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Activation Order Group 추출 스크립트
|
||||
|
||||
Blueprint.json에서 스토커별 스킬의 ActivationOrderGroup 값을 추출합니다.
|
||||
|
||||
사용법:
|
||||
python extract_activation_order_groups.py <Blueprint.json 경로>
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
def extract_activation_order_groups(json_path):
|
||||
"""Blueprint.json에서 ActivationOrderGroup 추출"""
|
||||
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
blueprints = json.load(f)
|
||||
|
||||
# 스토커별 스킬 그룹화
|
||||
stalker_skills = defaultdict(list)
|
||||
|
||||
stalkers = ['Hilda', 'Urud', 'Nave', 'Baran', 'Rio', 'Clad', 'Rene', 'Sinobu', 'Lian', 'Cazimord']
|
||||
|
||||
for bp in blueprints:
|
||||
asset_name = bp.get('AssetName', '')
|
||||
|
||||
# GA_Skill_{Stalker}_ 패턴 찾기
|
||||
if asset_name.startswith('GA_Skill_'):
|
||||
for stalker in stalkers:
|
||||
if f'_{stalker}_' in asset_name:
|
||||
# ActivationOrderGroup 찾기
|
||||
activation_order = None
|
||||
for var in bp.get('Variables', []):
|
||||
if var.get('Name') == 'ActivationOrderGroup':
|
||||
activation_order = var.get('DefaultValue', '0')
|
||||
break
|
||||
|
||||
skill_name = asset_name.replace(f'GA_Skill_{stalker}_', '')
|
||||
|
||||
stalker_skills[stalker].append({
|
||||
'skill': skill_name,
|
||||
'order_group': int(activation_order) if activation_order else 0,
|
||||
'full_name': asset_name
|
||||
})
|
||||
|
||||
return stalker_skills
|
||||
|
||||
|
||||
def print_stalker_skills(stalker_skills):
|
||||
"""스토커별 스킬과 ActivationOrderGroup 출력"""
|
||||
|
||||
print("\n스토커별 Activation Order Group")
|
||||
print("=" * 100)
|
||||
|
||||
for stalker, skills in sorted(stalker_skills.items()):
|
||||
print(f"\n{stalker}:")
|
||||
|
||||
# Order Group별로 정렬
|
||||
skills_by_group = defaultdict(list)
|
||||
for skill in skills:
|
||||
skills_by_group[skill['order_group']].append(skill['skill'])
|
||||
|
||||
for group in sorted(skills_by_group.keys(), reverse=True):
|
||||
print(f" Group {group}: {', '.join(sorted(skills_by_group[group]))}")
|
||||
|
||||
|
||||
def print_statistics(stalker_skills):
|
||||
"""통계 정보 출력"""
|
||||
|
||||
print("\n\n통계")
|
||||
print("=" * 100)
|
||||
|
||||
# 각 Group별 사용 빈도
|
||||
group_count = defaultdict(int)
|
||||
for stalker, skills in stalker_skills.items():
|
||||
for skill in skills:
|
||||
group_count[skill['order_group']] += 1
|
||||
|
||||
print("\nGroup별 스킬 수:")
|
||||
for group in sorted(group_count.keys(), reverse=True):
|
||||
print(f" Group {group}: {group_count[group]}개")
|
||||
|
||||
# 스토커별 스킬 수
|
||||
print("\n스토커별 스킬 수:")
|
||||
for stalker, skills in sorted(stalker_skills.items(), key=lambda x: len(x[1]), reverse=True):
|
||||
print(f" {stalker}: {len(skills)}개")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("사용법: python extract_activation_order_groups.py <Blueprint.json 경로>")
|
||||
sys.exit(1)
|
||||
|
||||
json_path = Path(sys.argv[1])
|
||||
|
||||
if not json_path.exists():
|
||||
print(f"오류: 파일을 찾을 수 없습니다: {json_path}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"분석 중: {json_path}")
|
||||
|
||||
stalker_skills = extract_activation_order_groups(json_path)
|
||||
|
||||
print(f"\n총 {sum(len(skills) for skills in stalker_skills.values())}개의 스킬 발견")
|
||||
|
||||
print_stalker_skills(stalker_skills)
|
||||
print_statistics(stalker_skills)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
69
분석도구/extract_skill_cancel_windows.py
Normal file
69
분석도구/extract_skill_cancel_windows.py
Normal file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
스킬 캔슬 윈도우 추출 스크립트
|
||||
|
||||
AnimMontage.json에서 ANS_SkillCancel_C 노티파이를 가진 몽타주를 찾아
|
||||
캔슬 가능 시간 구간을 추출합니다.
|
||||
|
||||
사용법:
|
||||
python extract_skill_cancel_windows.py <AnimMontage.json 경로>
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def extract_cancel_windows(json_path):
|
||||
"""AnimMontage.json에서 스킬 캔슬 윈도우 추출"""
|
||||
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
montages = json.load(f)
|
||||
|
||||
cancel_montages = []
|
||||
|
||||
for montage in montages:
|
||||
asset_name = montage.get('AssetName', '')
|
||||
|
||||
# ANS_SkillCancel_C 노티파이 찾기
|
||||
for notify in montage.get('AnimNotifies', []):
|
||||
if notify.get('NotifyStateClass') == 'ANS_SkillCancel_C':
|
||||
trigger_time = notify['TriggerTime']
|
||||
duration = notify['Duration']
|
||||
|
||||
cancel_montages.append({
|
||||
'montage': asset_name,
|
||||
'start': trigger_time,
|
||||
'end': trigger_time + duration,
|
||||
'duration': duration
|
||||
})
|
||||
|
||||
return cancel_montages
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("사용법: python extract_skill_cancel_windows.py <AnimMontage.json 경로>")
|
||||
sys.exit(1)
|
||||
|
||||
json_path = Path(sys.argv[1])
|
||||
|
||||
if not json_path.exists():
|
||||
print(f"오류: 파일을 찾을 수 없습니다: {json_path}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"분석 중: {json_path}")
|
||||
print("-" * 80)
|
||||
|
||||
cancel_windows = extract_cancel_windows(json_path)
|
||||
|
||||
print(f"\n총 {len(cancel_windows)}개의 스킬 캔슬 윈도우 발견\n")
|
||||
|
||||
for item in cancel_windows:
|
||||
print(f"{item['montage']}")
|
||||
print(f" 캔슬 구간: {item['start']:.3f}s ~ {item['end']:.3f}s (지속: {item['duration']:.3f}s)")
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user