57 lines
3.8 KiB
Python
57 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Extract AVA2's active biology table and command body, retaining reference provenance.
|
|
Only command dispatch, notification transport and three PORT point numbers are adapted.
|
|
"""
|
|
import argparse, hashlib, json, re
|
|
from pathlib import Path
|
|
HERE=Path(__file__).resolve().parent
|
|
NAMES={
|
|
'POINT_DEF_GRADE_BONUS':'防御力','POINT_ATT_GRADE_BONUS':'攻击力','POINT_ATTBONUS_MONSTER':'对怪物伤害 %',
|
|
'POINT_ATTBONUS_STONE':'对陨石伤害 %','POINT_ATTBONUS_BOSS':'对 Boss 伤害 %','POINT_MAX_HP':'生命值',
|
|
'POINT_CASTING_SPEED':'施法速度','POINT_RESIST_WARRIOR':'战士抗性 %','POINT_RESIST_ASSASSIN':'忍者抗性 %',
|
|
'POINT_RESIST_SURA':'修罗抗性 %','POINT_RESIST_SHAMAN':'萨满抗性 %','POINT_ATTBONUS_WARRIOR':'对战士伤害 %',
|
|
'POINT_ATTBONUS_ASSASSIN':'对忍者伤害 %','POINT_ATTBONUS_SURA':'对修罗伤害 %','POINT_ATTBONUS_SHAMAN':'对萨满伤害 %',
|
|
'POINT_RESIST_HUMAN':'半人抗性 %','POINT_MELEE_MAGIC_ATT_BONUS_PER':'近战及魔法攻击 %','POINT_ATTBONUS_HUMAN':'对半人伤害 %'}
|
|
|
|
def extract(reference):
|
|
constants=(reference/'constants.cpp').read_bytes().decode('latin1')
|
|
table=re.search(r'const DWORD bio_data\[\]\[17\] = \{(.*?)\n\};',constants,re.S).group(1)
|
|
rows=[]
|
|
for match in re.finditer(r'\{([^{}]+)\}', table):
|
|
values=[x.strip() for x in match[1].split(',')]; assert len(values)==17
|
|
rows.append([v if v.startswith('POINT_') else int(v) for v in values])
|
|
assert len(rows)==14
|
|
return rows
|
|
|
|
def generate(reference,output):
|
|
rows=extract(reference)
|
|
source=(reference/'cmd_general.cpp').read_bytes().decode('latin1').replace('\r','')
|
|
start=source.index('ACMD(do_bio)\n');end=source.index('\n#endif',start)
|
|
body=source[start:end]
|
|
# Maintain the upstream algorithm verbatim. Adapter guards live outside this function.
|
|
body=body.replace('ACMD(do_bio)', 'static ACMD(do_ava2_bio)')
|
|
body=body.replace('split_argument(argument, vecArgs);','BioSplitArgument(argument, vecArgs);')
|
|
notices={'562':'level','563':'material','564':'cooldown','565':'success','566':'failure','567':'stone','568':'reward','569':'next','570':'complete'}
|
|
for key,name in notices.items():
|
|
body=body.replace('CHAT_TYPE_INFO, "'+key+'"','CHAT_TYPE_COMMAND, "BioNotice '+name+'"')
|
|
body=body.replace('CHAT_TYPE_INFO, "'+key+' I%d"','CHAT_TYPE_COMMAND, "BioNotice '+name+' %d"')
|
|
body=body.replace('CHAT_TYPE_INFO, "'+key+' E%d:%d"','CHAT_TYPE_COMMAND, "BioNotice '+name+' %d %d"')
|
|
body=body.replace('pointToApply(', 'BioPointIdentity(')
|
|
# The level notice in upstream forgot its printf placeholder. Keep its level argument visible.
|
|
body=body.replace('"BioNotice level"','"BioNotice level %d"')
|
|
table='static const unsigned bio_data[][17] = {\n'+''.join(' {'+', '.join(map(str,row))+'},\n' for row in rows)+'};\nstatic const unsigned bio_max = 14;\n'
|
|
generated='// Generated from AVA2 constants.cpp + cmd_general.cpp by import_ava2.py.\n'+table+body+'\n'
|
|
output.mkdir(parents=True,exist_ok=True)
|
|
(output/'ava2_biolog_core.h').write_text(generated)
|
|
catalog=[]
|
|
for i,row in enumerate(rows[1:],1):
|
|
catalog.append(dict(index=i,level=row[0],material=row[1],count=row[2],cooldown=row[3],chance=row[4],stone=row[5],
|
|
bonuses=[dict(point=row[j],label=NAMES[row[j]],value=row[j+1]) for j in (6,8,10,12) if row[j]],choose=bool(row[14]),enhancer=row[15],skip=row[16]))
|
|
(output/'catalog.json').write_text(json.dumps(catalog,ensure_ascii=False,indent=2)+'\n')
|
|
(output/'reference.json').write_text(json.dumps({name:hashlib.sha256((reference/name).read_bytes()).hexdigest() for name in ('constants.cpp','cmd_general.cpp','char.cpp')},indent=2)+'\n')
|
|
return catalog
|
|
|
|
if __name__=='__main__':
|
|
parser=argparse.ArgumentParser();parser.add_argument('reference',type=Path);parser.add_argument('output',type=Path)
|
|
args=parser.parse_args();generate(args.reference,args.output)
|