Загрузка данных


#include <windows.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <chrono>

namespace fs = std::filesystem;

HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
constexpr WORD Gray = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
constexpr WORD White = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
constexpr WORD DarkGray = FOREGROUND_INTENSITY;
constexpr WORD Cyan = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
constexpr WORD DarkCyan = FOREGROUND_GREEN | FOREGROUND_BLUE;
constexpr WORD Red = FOREGROUND_RED | FOREGROUND_INTENSITY;
constexpr WORD DarkRed = FOREGROUND_RED;

void color(WORD value)
{
    SetConsoleTextAttribute(output, value);
}

void wait(int milliseconds)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}

int consoleWidth()
{
    CONSOLE_SCREEN_BUFFER_INFO info{};
    if (!GetConsoleScreenBufferInfo(output, &info))
        return 80;
    return info.srWindow.Right - info.srWindow.Left + 1;
}

void clearScreen()
{
    CONSOLE_SCREEN_BUFFER_INFO info{};
    if (!GetConsoleScreenBufferInfo(output, &info))
        return;

    DWORD width = static_cast<DWORD>(info.srWindow.Right - info.srWindow.Left + 1);
    COORD start{};
    DWORD written = 0;

    for (SHORT y = info.srWindow.Top; y <= info.srWindow.Bottom; ++y)
    {
        start.X = info.srWindow.Left;
        start.Y = y;
        FillConsoleOutputCharacterA(output, ' ', width, start, &written);
        FillConsoleOutputAttribute(output, Gray, width, start, &written);
    }

    COORD home{ info.srWindow.Left, info.srWindow.Top };
    SetConsoleCursorPosition(output, home);
    color(Gray);
}

void cursorVisible(bool visible)
{
    CONSOLE_CURSOR_INFO info{};
    if (GetConsoleCursorInfo(output, &info))
    {
        info.bVisible = visible;
        SetConsoleCursorInfo(output, &info);
    }
}

int leftPadding(const std::string& text)
{
    return text.size() >= static_cast<size_t>(consoleWidth())
        ? 0
        : (consoleWidth() - static_cast<int>(text.size())) / 2;
}

void centered(const std::string& text, WORD shade = Gray)
{
    color(shade);
    std::cout << std::string(leftPadding(text), ' ') << text << '\n' << std::flush;
}

void centeredRaw(const std::string& text, WORD shade = Gray)
{
    color(shade);
    std::cout << std::string(leftPadding(text), ' ') << text << std::flush;
}

void rewriteCentered(const std::string& text, WORD shade)
{
    color(shade);
    std::cout << '\r' << std::string(leftPadding(text), ' ') << text << std::flush;
}

void header(const std::string& first, const std::string& second)
{
    const std::string border = "+----------------------------------------------------------+";
    centered(border, DarkCyan);
    centered("|" + std::string(56, ' ') + "|", DarkCyan);

    auto frameLine = [](const std::string& text)
    {
        std::string value = text.substr(0, 56);
        int pad = (56 - static_cast<int>(value.size())) / 2;
        value = std::string(pad, ' ') + value;
        value += std::string(56 - value.size(), ' ');
        centered("|" + value + "|", Cyan);
    };

    frameLine(first);
    frameLine(second);
    centered("|" + std::string(56, ' ') + "|", DarkCyan);
    centered(border, DarkCyan);
    centered("");
}

bool yes(const std::string& value)
{
    return value == "Y" || value == "y" ||
           value == "YES" || value == "yes" ||
           value == "Yes";
}

bool ask(const std::string& prompt, std::string& answer)
{
    centered(prompt, White);
    centeredRaw("> ", Cyan);
    color(Gray);
    return static_cast<bool>(std::getline(std::cin, answer));
}

std::string dotted(const std::string& text, size_t count)
{
    std::string result = text;
    for (size_t i = 0; i < count && i < result.size(); ++i)
        if (result[i] != ' ')
            result[i] = '.';
    return result;
}

std::string blanked(const std::string& text, size_t count)
{
    std::string result = text;
    for (size_t i = 0; i < count && i < result.size(); ++i)
        if (result[i] != ' ')
            result[i] = ' ';
    return result;
}

void eraseLine(const std::string& text, int speed = 8)
{
    centeredRaw(text, White);

    for (size_t i = 1; i <= text.size(); ++i)
    {
        rewriteCentered(dotted(text, i), i < text.size() / 2 ? Red : DarkRed);
        wait(speed);
    }

    for (size_t i = 1; i <= text.size(); ++i)
    {
        rewriteCentered(blanked(dotted(text, text.size()), i), DarkGray);
        wait(speed / 2 + 1);
    }

    std::cout << '\n' << std::flush;
}

void eraseSection(
    const std::string& title,
    const std::string& subtitle,
    const std::vector<std::string>& rows)
{
    centered("");
    header(title, "RECORD INTEGRITY: FAILING");
    centered(subtitle, DarkGray);
    centered("");

    for (const auto& row : rows)
    {
        eraseLine(row);
        wait(100);
    }
}

fs::path executableDirectory()
{
    std::vector<wchar_t> buffer(32768);
    DWORD length = GetModuleFileNameW(
        nullptr,
        buffer.data(),
        static_cast<DWORD>(buffer.size()));

    if (length == 0 || length >= static_cast<DWORD>(buffer.size()))
        return {};

    return fs::path(std::wstring(buffer.data(), length)).parent_path();
}

bool sealRecord(const fs::path& marker)
{
    std::ofstream file(marker, std::ios::binary);

    if (!file)
        return false;

    file.close();
    SetFileAttributesW(marker.c_str(), FILE_ATTRIBUTE_HIDDEN);
    return true;
}

void cancel()
{
    centered("");
    header("REQUEST WITHDRAWN", "NO CHANGE COMMITTED");
    centered("The record remains.", Gray);
    wait(1300);
    clearScreen();
}

int main()
{
    fs::path directory = executableDirectory();

    if (directory.empty())
        return 0;

    fs::path marker = directory / L".cathy_erased";
    std::error_code error;

    if (fs::exists(marker, error))
        return 0;

    SetConsoleTitleA("MIRROR-WORLD TERMINAL // CATHY");
    cursorVisible(false);
    clearScreen();

    header("MIRROR-WORLD TERMINAL", "CANTO VI // FINAL RECORD");
    centered("IDENTITY INDEX", Cyan);
    centered("");
    centered("MIRROR INSTANCES : 07", Gray);
    centered("MEMORY TRACE     : PRESENT", Gray);
    centered("CONTINUITY       : UNBROKEN", Gray);
    centered("ERASURE          : NOT STARTED", DarkGray);
    centered("");
    centered("A name persists across every reflection.", DarkGray);
    centered("An absence can be written across them all.", DarkGray);
    centered("");

    std::string answer;

    if (!ask("Are you sure you wanna erase all Cathy? [Y/N]", answer)
        || !yes(answer))
    {
        cancel();
        cursorVisible(true);
        color(Gray);
        return 0;
    }

    centered("");
    header("CONFIRMATION REQUIRED", "IRREVERSIBLE OPERATION");
    centered("This request includes every known reflection.", Gray);
    centered("There will be no record left to return to.", DarkGray);
    centered("");

    if (!ask("Type CLEAR ALL CATHY to proceed.", answer)
        || answer != "CLEAR ALL CATHY")
    {
        cancel();
        cursorVisible(true);
        color(Gray);
        return 0;
    }

    centered("");
    header("01 / MIRROR INDEX", "ALL INSTANCES ARE CONNECTED");
    centered("The same name. Different worlds.", DarkGray);
    centered("");

    for (int i = 1; i <= 7; ++i)
    {
        std::string row =
            "MIRROR-0" + std::to_string(i) +
            "  |  C A T H Y  |  PRESENT";

        eraseLine(row, 6);
        wait(80);
    }

    eraseSection(
        "02 / MEMORY TRACE",
        "Some things remain even after the house is gone.",
        {
            "THE WORDS HE NEVER SAID",
            "THE HOUSE ABOVE THE MOORS",
            "A PROMISE LEFT UNFINISHED",
            "THE PATH THAT LED HIM HOME",
            "THE PLACE SHE HELD IN HIS HEART"
        });

    eraseSection(
        "03 / MIRROR ECHOES",
        "Every possible world is being made quiet.",
        {
            "ONE WORLD AFTER ANOTHER",
            "A NAME SPOKEN IN EVERY MIRROR",
            "A FUTURE THAT WAS NEVER THEIRS",
            "THE REASON FOR HIS LONG RETURN",
            "THE MEMORY THAT OUTLIVED THE WORLD"
        });

    eraseSection(
        "04 / CONCEPTUAL RECORD",
        "The record is the last thing to disappear.",
        {
            "IDENTITY   : CATHY",
            "INSTANCES  : ALL",
            "MEMORY     : PRESENT",
            "CONTINUITY : UNBROKEN",
            "RECORD     : RETAINED"
        });

    if (!sealRecord(marker))
    {
        centered("");
        header("COMMIT INTERRUPTED", "PERSISTENCE FAILED");
        centered("The erasure could not be sealed.", Red);
        centered("No permanent change was committed.", Gray);
        wait(2200);
        clearScreen();
        cursorVisible(true);
        color(Gray);
        return 1;
    }

    wait(350);
    clearScreen();
    wait(700);
    cursorVisible(true);
    color(Gray);
    return 0;
}