かけらの記録ノート

かけらの記録ノート

主にポケモンの乱数について語るブログ

【XD乱数】いますぐつないで

「いますぐバトル」と「つないでバトル」に入った時の生成処理です。

ポケモンXDが流行ってるらしいので調べた。
今回は日本版で調査したので、逆に欧州だとうまく動かない可能性があります。おそらく大丈夫だと思われるが...
なお、表裏IDが主人公のを参照してるかは調べてません。

def EnterQuickBattle(RNG):

    RNG.Advance(122)

    for i in range(4):
        tid = RNG.Advance(1) >> 16
        sid = RNG.Advance(1) >> 16

        for j in range(2):
            RNG.Advance(5)
            GeneratePID(RNG, tid, sid)
            GenerateEV(RNG)

    return RNG

def EnterConnectBattle(RNG):

    RNG.Advance(122)

    tid = RNG.Advance(1) >> 16
    sid = RNG.Advance(1) >> 16
    for j in range(3):
        RNG.Advance(5)
        GeneratePID(RNG, tid, sid)
        GenerateEV(RNG)
    generate_list = [
        ["♂1♀1","♂","わんぱく"],
        ["♂1♀1","♂","わんぱく"],
        ["♂3♀1","♂","わんぱく"]
    ]
    for j in range(3):
        RNG.Advance(5)
        pid = GeneratePID(RNG, tid, sid, genderRatio=generate_list[j][0], gender=generate_list[j][1], nature=generate_list[j][2])

    tid = RNG.Advance(1) >> 16
    sid = RNG.Advance(1) >> 16

    RNG.Advance(5)
    pid = GeneratePID(RNG, tid, sid)
    GenerateEV(RNG)

    generate_list = [
        ["-","-","むじゃき"],
    ]
    RNG.Advance(5)
    pid = GeneratePID(RNG, tid, sid, genderRatio=generate_list[0][0], gender=generate_list[0][1], nature=generate_list[0][2])

    generate_list = [
        ["-","-","のんき"],
        ["♂1♀1","♂","うっかりや"],
    ]
    tid = RNG.Advance(1) >> 16
    sid = RNG.Advance(1) >> 16
    for j in range(2):
        RNG.Advance(5)
        pid = GeneratePID(RNG, tid, sid, genderRatio=generate_list[j][0], gender=generate_list[j][1], nature=generate_list[j][2])

    tid = RNG.Advance(1) >> 16
    sid = RNG.Advance(1) >> 16
    for j in range(2):
        RNG.Advance(5)
        pid = GeneratePID(RNG, tid, sid)
        GenerateEV(RNG)
    return RNG

いますぐバトルは単純に4×2匹の性格値と努力値を生成してるだけでした。
つないでバトルは所々で性格が固定されてたり努力値が生成されたりして謎です。
いみわからん生成してるせいで調査が少し大変だった。

「つないでバトル」内で、設定の変更によるセーブによる消費と名前選択時の不定消費が使えることが分かりましたが、何かに使えるかは分かりません。
対戦プロファイルの名前を変えるときと、メモカに保存するときに発生します。

日本版ではタイトルでの2消費が使えないことによって消費の微調整が面倒でしたが、これらを使えばちょっとはマシになるんじゃないでしょうか。
XDは色回避処理のせいでモチベがないので、ツールの作成はしません。興味のある人は参考にして実装してみてください。

以下使用した汎用関数です。

def GetGender(pid, ratio):
    r = pid & 0xFF
    if(ratio == "-"):
        g = "-"
    elif(ratio == "♀" or
        (ratio == "♂1♀3" and r <= 190) or
        (ratio == "♂1♀1" and r <= 126) or
        (ratio == "♂3♀1" and r <= 62) or
        (ratio == "♂8♀1" and r <= 30)):
            g = "♀"
    else:
        g = "♂"
    return g

def GetNature(pid):
    n = pid % 25
    return NATURE[n]

def ShinyCheck(pid, tid, sid):
    return tid ^ sid ^ (pid & 0xFFFF) ^ (pid >> 16)

def GeneratePID(RNG, tid, sid, isshiny=None, gender=None, genderRatio="-", nature=None):
    while(True):
        hid = RNG.Advance(1) >> 16
        lid = RNG.Advance(1) >> 16
        pid = (hid << 16) | lid

        if(gender is not None):

            if(GetGender(pid, genderRatio) != gender):
                continue

        if(nature is not None):
            if(GetNature(pid) != nature):
                continue

        if(isshiny is not None):
            if(not isshiny):
                if(not ShinyCheck(pid, tid, sid) < 8):
                    return pid
                continue
            elif(isshiny):
                if(ShinyCheck(pid, tid, sid) < 8):
                    return pid
                continue
            else:
                return pid
        break

    return pid


def GenerateEV(RNG):
    ev = np.zeros((6), dtype=np.uint8)
    for j in range(101):
        sumev = 0
        for k in range(6):
            ev[k] += (RNG.Advance(1) >> 16) & 0xFF
            sumev += ev[k]
        if(sumev <= 510):
            return ev
        else:
            if(j >= 100):
                continue
            ev.fill(0)
    return ev