from __future__ import annotations import os import sys from nte_history_exporter.constants import EXPORTER_VERSION, GAME_NAME WIDTH = 58 RESET = "\x1b[0m" BOLD = "\x1b[1m" DIM = "\x1b[2m" CYAN = "\x1b[36m" GREEN = "\x1b[32m" YELLOW = "\x1b[33m" _ansi: bool | None = None def _enable_ansi() -> bool: if not hasattr(sys.stdout, "isatty") or not sys.stdout.isatty(): return False if os.name != "nt": return True try: import ctypes kernel32 = ctypes.windll.kernel32 handle = kernel32.GetStdHandle(-11) mode = ctypes.c_uint32() if not kernel32.GetConsoleMode(handle, ctypes.byref(mode)): return False ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 return bool(kernel32.SetConsoleMode(handle, mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) except Exception: return False def ansi_enabled() -> bool: global _ansi if _ansi is None: _ansi = _enable_ansi() return _ansi def style(text: str, *codes: str) -> str: if not codes or not ansi_enabled(): return text return "".join(codes) + text + RESET def rule(char: str = "-") -> str: return style(char * WIDTH, DIM) def print_banner() -> None: print() print(rule("=")) print(style(f" NTE History Exporter v{EXPORTER_VERSION}", BOLD, CYAN)) print(style(f" {GAME_NAME} pull history -> tracker JSON", DIM)) print(rule("=")) def print_live_instructions(local_ip: str) -> None: print() print(style(" Listening on ", DIM) + style(local_ip, BOLD)) print() print(style(" How to export your pull history", BOLD)) print(" 1. This tool must be running BEFORE you press Start on") print(" the game's main menu, or the game connection cannot") print(" be captured. Already in game? Log out to the main") print(" menu and enter again.") print(" 2. Open a supported history screen:") print(style(" Monopoly > Standard Board history", CYAN)) print(style(" Monopoly > Limited Character Board history", CYAN)) print(style(" Gashapon > Arc Miracle Box history", CYAN)) print(" 3. Start at page 1 and scroll down through every page") print(" you want exported.") print(" 4. Scroll one page past where you plan to stop so the") print(" last pull group can be confirmed as complete.") print(" 5. You can open several boards in the same session.") print() print(style(" Waiting for history pages... press any key here when done.", BOLD, GREEN)) print(rule()) def print_page_captured(label: str, page: int | None) -> None: print(style(" + ", GREEN, BOLD) + label + style(f" page {page}", DIM)) def print_results_header() -> None: print() print(rule()) print(style(" Results", BOLD)) print(rule()) def print_export_summary(name: str, decoded: int, exported: int, skipped: int) -> None: counts = [ style(f"decoded {decoded}", DIM), style(f"exported {exported}", GREEN, BOLD), style(f"skipped {skipped}", YELLOW if skipped else DIM), ] print(f" {name:<30}" + " ".join(counts)) def print_warning(code: str, reason: str, records: int | None = None) -> None: suffix = f" ({records} records)" if records is not None else "" print(style(f" ! {code}: {reason}{suffix}", YELLOW)) def print_note(text: str) -> None: print(style(f" {text}", DIM)) def print_success(text: str) -> None: print(style(f" {text}", GREEN, BOLD)) def print_problem(text: str) -> None: print(style(f" {text}", YELLOW, BOLD)) def print_boxed(lines: list[str], *codes: str) -> None: inner = WIDTH - 4 border = " +" + "-" * (WIDTH - 2) + "+" print(style(border, *codes)) for line in lines: print(style(" | " + line.ljust(inner) + " |", *codes)) print(style(border, *codes)) # Warning codes for an oldest timestamp group that was exported despite possibly # being an unfinished 10-pull. The exported rows are stable, so the warning is # informational and the user can ignore it once the rest is captured. INCOMPLETE_EXPORT_CODES = { "INCOMPLETE_TIMESTAMP_GROUP_EXPORTED", "INCOMPLETE_ARC_10_PULL_EXPORTED", } def maybe_print_incomplete_hint(warnings: list[dict]) -> None: if not any(w.get("code") in INCOMPLETE_EXPORT_CODES for w in warnings): return print() print_boxed( [ "The INCOMPLETE_..._EXPORTED warning above is safe", "to ignore if the partial 10-pull it captured is", "already in your tracker. Otherwise restart", "the capture and go to a further page", ], GREEN, BOLD, )