#!/usr/bin/env python3
"""
Nile.exe compatibility patch — fixes an instant startup crash
(STATUS_ACCESS_VIOLATION / 0xC0000005 inside USER32.dll, wsprintfA)
on modern Windows (tested on Windows 10 21H2 / build 19044+).

Root cause: at VA 0x0040CF94, the game reads the first 4 bytes of the
static string buffer "ImpDebug.out" (located at 0x00511FE0) and misuses
them as a pointer, instead of using the buffer's own address. This is
passed to wsprintfA as the output buffer, causing a write to the bogus
address 0x44706D49 ("ImpD") on every launch.

Fix: change opcode 0xA1 ("mov eax, [0x511FE0]") to 0xB8
("mov eax, 0x511FE0") at file offset 0x0000C394. A 1-byte change;
instruction length and all following code/offsets are unaffected.

Usage:
    python patch_nile.py "C:\\path\\to\\Nile.exe"

The script verifies the expected original byte before patching and
refuses to touch a file that doesn't match (e.g. if already patched,
or a different build/version).
"""
import sys

PATCH_OFFSET = 0x0000C394
ORIGINAL_BYTE = 0xA1
PATCHED_BYTE = 0xB8
EXPECTED_TAIL = bytes([0xE0, 0x1F, 0x51, 0x00])  # operand: address 0x00511FE0


def main():
    if len(sys.argv) != 2:
        print(f"Usage: python {sys.argv[0]} <path to Nile.exe>")
        sys.exit(1)

    path = sys.argv[1]
    with open(path, "rb") as f:
        data = bytearray(f.read())

    if len(data) <= PATCH_OFFSET + 5:
        print("ERROR: file too small, this doesn't look like the expected Nile.exe")
        sys.exit(1)

    current = data[PATCH_OFFSET]
    tail = bytes(data[PATCH_OFFSET + 1:PATCH_OFFSET + 5])

    if current == PATCHED_BYTE and tail == EXPECTED_TAIL:
        print("Already patched — nothing to do.")
        return

    if current != ORIGINAL_BYTE or tail != EXPECTED_TAIL:
        print(f"ERROR: unexpected bytes at offset 0x{PATCH_OFFSET:X}: "
              f"{current:02X} {tail.hex()} (expected {ORIGINAL_BYTE:02X} {EXPECTED_TAIL.hex()}). "
              "This may be a different build/version of Nile.exe. Aborting.")
        sys.exit(1)

    data[PATCH_OFFSET] = PATCHED_BYTE

    with open(path, "wb") as f:
        f.write(data)

    print(f"Patched successfully: offset 0x{PATCH_OFFSET:X} "
          f"{ORIGINAL_BYTE:02X} -> {PATCHED_BYTE:02X}")


if __name__ == "__main__":
    main()
