# -*- coding: utf-8 -*-
r"""Extrai a arvore de skills de cada classe.

    python tools/extrair_skilltree.py  ->  server/Data/Skills/SkillArvore.ini

DE ONDE VEM. Ha um SkillTree_<classe>.lod por classe em ResUnpak/Interface/IE_Lod --
sete classes base (100 a 800) e as variantes de avanco (110, 111, 112, 120...).

DECIFRA COM pular_zero=False, como o skillLevel. Com o modo padrao sai ruido.

FORMATO, medido em 30/08 nas classes 400 e 600:

    @0  u32   20101118   carimbo de versao, igual em todas
    @4  u32   contagem
    @8  N registos de 12 bytes: (skill_id, x, y)

Os dois ultimos sao a posicao do icone na janela da arvore -- valores como 21, 62, 75, 103,
129, 144, que se repetem entre classes. Nao sao nivel nem custo.

    classe 400   6 skills   7001 7005 7002 7003 7004 7006
    classe 600   5 skills   11001 11002 11003 11004 11005

PARA QUE SERVE. O pacote 05 05 (lista de skills do personagem) vinha do stream capturado, ou
seja TODA a gente recebia as skills da personagem gravada -- uma Maga. O jogador deu por
isso: "so ta soltando skill da maga".
"""
import io
import os
import struct
import sys

RAIZ = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(RAIZ, "tools"))
import lod_crypto as L                                              # noqa: E402

PASTA = r"C:\Games\Axion\ResUnpak\Interface\IE_Lod"
CARIMBO = 20101118
TAM = 12


def arvore(classe: int):
    """[(skill_id, x, y)] da classe, ou [] se nao houver ficheiro."""
    for suf in ("_pt", ""):
        p = os.path.join(PASTA, "SkillTree_%d.lod%s" % (classe, suf))
        if os.path.isfile(p):
            break
    else:
        return []
    d = L.decrypt_lod_stream(open(p, "rb").read(), pular_zero=False)
    if len(d) < 8 or struct.unpack_from("<I", d, 0)[0] != CARIMBO:
        return []
    n = struct.unpack_from("<I", d, 4)[0]
    if not 0 < n < 200:
        return []
    saida = []
    for k in range(n):
        o = 8 + k * TAM
        if o + TAM > len(d):
            break
        saida.append(struct.unpack_from("<III", d, o))
    return saida


def main() -> int:
    import glob
    import re
    classes = sorted({int(re.search(r"SkillTree_(\d+)", os.path.basename(f)).group(1))
                      for f in glob.glob(os.path.join(PASTA, "SkillTree_*.lod*"))})
    nl, tb = chr(10), chr(9)
    destino = os.path.join(RAIZ, "server", "Data", "Skills", "SkillArvore.ini")
    linhas = 0
    with io.open(destino, "w", encoding="utf-8", newline="") as f:
        f.write("; SkillArvore -- que skills cada classe tem, do SkillTree_<classe>.lod." + nl)
        f.write("; Gerado por tools/extrair_skilltree.py. Ver o cabecalho dessa ferramenta." + nl)
        f.write("; x e y sao a posicao do icone na janela, nao nivel nem custo." + nl)
        f.write(tb.join(["//classe", "ordem", "skill_id", "x", "y"]) + nl)
        for cl in classes:
            for k, (sid, x, y) in enumerate(arvore(cl)):
                f.write(tb.join([str(cl), str(k), str(sid), str(x), str(y)]) + nl)
                linhas += 1
    print("classes: %d, linhas: %d em %s" % (len(classes), linhas, os.path.normpath(destino)))
    for cl in (100, 200, 300, 400, 500, 600, 800):
        a = arvore(cl)
        print("   classe %-4d %d skills: %s" % (cl, len(a), [s for s, _x, _y in a]))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
