# Q9: FUN_18004c180 builds the squad-service object registered into DAT_1802dfd18.
# Recover its vtable, then decompile AddPlayerToSquad(+0xc8) and SaveCurrentSquad
# (+0x28) -- the two slots that decide whether PUT /squad is ever issued.
out = open("/tmp/ghidra_fut/squad_service.txt", "w")
P = lambda *a: print(*a, file=out)

P("=== factory FUN_18004c180 ===")
P(dec(0x18004c180))

# find vtable pointers written by the factory
f = func(0x18004c180)
cands = {}
for a in f.getBody().getAddresses(True):
    ins = listing.getInstructionAt(a)
    if ins is None:
        continue
    for r in ins.getReferencesFrom():
        t = int(r.getToAddress().getOffset())
        if 0x1801e5000 <= t <= 0x1802891ff:
            cands[t] = cands.get(t, 0) + 1

P("\n=== vtable candidates referenced by the factory ===")
best = None
for t, n in sorted(cands.items()):
    try:
        fns = [fm.getFunctionAt(addr(qword(t + i * 8))) for i in range(6)]
    except Exception:
        continue
    nf = sum(1 for x in fns if x)
    if nf >= 5:
        P("  %#x  (%d/6 fnptrs, %d refs)" % (t, nf, n))
        if best is None:
            best = t

SLOTS = {0x20: "SaveSquad", 0x28: "SaveCurrentSquad", 0x30: "RemovePlayer",
         0x40: "GetCurrentSquadID?", 0x48: "GetCurrentSquadChemistry",
         0x58: "GetCurrentSquadData", 0x80: "GetSquadList", 0x88: "GetSquads",
         0x90: "SelectSquadById", 0xa8: "IsCardInSquad", 0xb8: "GetSquadLineup",
         0xc0: "LoadActiveSquad", 0xc8: "AddPlayerToSquad"}

for t in sorted(cands):
    try:
        fns = [fm.getFunctionAt(addr(qword(t + i * 8))) for i in range(6)]
    except Exception:
        continue
    if sum(1 for x in fns if x) < 5:
        continue
    P("\n=== VTABLE %#x ===" % t)
    for off, tgt, name in vtable(t, 40):
        tag = SLOTS.get(off, "")
        P("  +%#04x -> %#x %-16s %s" % (off, tgt, name, tag))
    P("\n--- key slot decompiles ---")
    for off in (0x28, 0xc8, 0x88, 0x80, 0x90, 0xc0):
        try:
            tgt = qword(t + off)
        except Exception:
            continue
        if not fm.getFunctionAt(addr(tgt)):
            continue
        P("### +%#04x %s -> %#x" % (off, SLOTS.get(off, ""), tgt))
        P(dec(tgt))
    break
out.close()
print("wrote squad_service.txt")
