"""D2 QUICK SELL, batch 3. ESTABLISHED SO FAR * item struct base in FUN_18013fe00 is RBP+0x160 (local_188). Therefore item+0x38 = discardValue as SENT BY THE SERVER (atom 0xd7) item+0x3c = discardValue COMPUTED LOCALLY, only when item+0x38 == 0 item+0x4c = cardtype (= FUN_1800d8330(cardsubtypeid)) item+0x50 = cardsubtypeid, item+0x54 = "level" query key item+0x58 = rareflag, item+0xb4 = rating * the local formula is round_half_up(rating * price / 100) where price = SELECT price FROM fcc_discardcoins WHERE cardtype==item+0x4c AND level==item+0x54 AND rare==item+0x58 * item+0x54 ("level") has EXACTLY ONE reference in the whole function and it is a READ; the only write is the 16-byte MOVDQA initialiser at 0x18013ffa1 from _DAT_1801f66a0 = 56 01 00 00 | 00 00 00 00 | ... so level is CONSTANT 0. * only two functions in the DLL carry the 0x326 (totalCredits) immediate: FUN_180127300 (DiscardCard) and FUN_1801279c0 (DiscardCardByRes). Both store to obj+0x28 with a plain MOV, never a read-modify-write. THIS BATCH A. who READS obj+0x28 on the DiscardCard server-call object? dump the class vtable at 0x180220488 (slot +0x08 == 0x180127300 confirms the base) and decompile every slot; likewise the DiscardCardByRes vtable located by searching .rdata for the qword 0x1801279c0. B. the FUT manager singleton: FUN_18011d780 writes DAT_1802e6398. find the concrete vtable, dump slots 0x9c0..0xa90, decompile 0xa08 / 0xa30 / 0xa48 and every neighbour whose body mentions a credit-looking field. C. who reads item+0x38 and item+0x3c? enumerate every function that both (i) references the item registration entry point mgr->vt[0xa08] target and (ii) contains a +0x38 / +0x3c memory operand. Also print the a08 target. D. Q3 bulk discard: resolve the class that owns FUN_180126f40 by searching .rdata for that qword, dump its vtable and decompile its url builder and response deserialiser, so the bulk request/response shape is read off code. E. print the raw .rdata around each RS4 discard literal so the class list is visible. CONTROLS * vtable slot +0x08 of 0x180220488 must equal 0x180127300 (already observed). * the .rdata qword search must find 0x180127300 at 0x180220490 (already observed via xrefs_to) -- same syntactic form as the searches for 0x1801279c0 and 0x180126f40, so a hit there validates the method. """ import traceback, os, struct OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/store/qs/" os.makedirs(OUT, exist_ok=True) def dump(tag, va, path=None): try: src = dec(va) except Exception as e: src = "// decompile threw %r" % (e,) print("=" * 78) print("%s %#x fname=%s len(src)=%d (FULL)" % (tag, va, fname(va), len(src))) print("=" * 78) print(src) if path: open(OUT + path, "w").write(src) return src def q(a): return struct.pack("