Загрузка данных
#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;
}