# -*- coding: utf-8 -*-
r"""Tira a velocidade de cada especie do npcInfo.lod do CLIENT.

    python tools/extrair_velocidades.py  ->  Data/Monsters/MobVelocidade.ini

PORQUE ESTE FICHEIRO E DIFERENTE DOS OUTROS. Tudo o resto neste projecto foi MEDIDO no fio,
com a incerteza que isso traz. Isto nao: sao os numeros que o proprio client usa, lidos da
tabela dele. Foi o jogador que apontou o caminho em 29/08: "no cliente deve ter a formula
exata, se no servidor fica diferente ocorre esse bug".

O REGISTO do npcInfo, decifrado nesse dia:

    +0    npc_id
    +64   100          (constante -- serve de assinatura para achar os registos)
    +68   nivel        (ja se sabia, estava anotado no Mob.ini)
    +100  f1  float
    +108  f2  float

A FORMULA, deduzida dos dois lados e validada contra o fio:

    passeio = f1 * f2            10,81 na maioria das especies
    corrida = f1 * f2 * f2       39,36 nas mesmas

O que fecha o raciocinio e a conta do avanco: o servidor declara um destino longe (23,33 a
passear) e o client anda a velocidade DELE. Em 0,613 s de intervalo isso da 10,81 * 0,613 =
6,63 de avanco por pacote -- e o avanco medido no fio do oficial e 6,67. A corrida da
39,36 * 0,537 = 21,13 contra os 21,33 medidos.

As medicoes do fio ficam 6 por cento abaixo destes valores, e a razao e conhecida: mede-se a
CORDA entre as origens de dois pacotes, e num percurso com curvas a corda e sempre menor que
o caminho. Por isso confia-se no numero do client e nao no medido.

O servidor usava 10,6 para as 926 especies.
"""
import collections
import io
import os
import struct
import sys

sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__))))
import lod_crypto                                                   # noqa: E402

LOD = r"C:\Games\Karos\ResUnpak\Interface\IE_Lod\npcInfo.lod_en"


def registos(d):
    """Offsets dos registos de monstro. A assinatura e (+56)==1 e (+64)==100."""
    saida = {}
    for i in range(0, len(d) - 120, 4):
        v = struct.unpack_from("<I", d, i)[0]
        if not (1000000 <= v <= 1999999):
            continue
        if (struct.unpack_from("<I", d, i + 64)[0] == 100
                and struct.unpack_from("<I", d, i + 56)[0] == 1):
            saida[v] = i
    return saida


def main() -> int:
    if not os.path.exists(LOD):
        print("nao encontrei %s" % LOD)
        return 1
    d = lod_crypto.decrypt_lod_stream(io.open(LOD, "rb").read(), pular_zero=True)
    regs = registos(d)
    print("%d especies no npcInfo" % len(regs))

    nomes = {}
    try:
        sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "server"))
        import data_files as D
        D.carregar()
        nomes = {r["mob_id"]: r.get("nome") for r in D.tabela("Mob") if r.get("mob_id")}
    except Exception:                                               # noqa: BLE001
        pass

    linhas = []
    for npc, o in sorted(regs.items()):
        f1 = struct.unpack_from("<f", d, o + 100)[0]
        f2 = struct.unpack_from("<f", d, o + 108)[0]
        if not (0.1 < f1 < 100 and 0.1 < f2 < 100):
            continue
        linhas.append((npc, f1 * f2, f1 * f2 * f2, nomes.get(npc) or ""))
    c = collections.Counter(round(x[1], 2) for x in linhas)
    print("velocidades de passeio distintas: %s" % c.most_common(8))

    destino = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                           "..", "server", "Data", "Monsters", "MobVelocidade.ini")
    nl = chr(10)
    tb = chr(9)      # tabulacao a serio, nao "backslash t"
    with io.open(destino, "w", encoding="utf-8", newline="") as f:
        f.write("; MobVelocidade -- do npcInfo.lod do CLIENT, nao medido no fio." + nl)
        f.write("; Gerado por tools/extrair_velocidades.py. Ver o cabecalho de la." + nl)
        f.write("; passeio = f1*f2   corrida = f1*f2*f2" + nl)
        f.write("//mob_id" + tb + "passeio" + tb + "corrida" + tb + "nome" + nl)
        for npc, p, c2, nome in linhas:
            f.write("%d" % npc + tb + "%.3f" % p + tb + "%.3f" % c2 + tb + nome + nl)
    print("escrito em %s  (%d especies)" % (os.path.normpath(destino), len(linhas)))
    return 0


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