From 1818ccda405dd7946d3680c3d5dffd2d1bdc3702 Mon Sep 17 00:00:00 2001 From: bitahajati Date: Mon, 13 Apr 2026 14:29:21 +0000 Subject: [PATCH] Upload files to "/" --- Breakout.cpp | 2362 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2362 insertions(+) create mode 100644 Breakout.cpp diff --git a/Breakout.cpp b/Breakout.cpp new file mode 100644 index 0000000..822a5da --- /dev/null +++ b/Breakout.cpp @@ -0,0 +1,2362 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "winmm.lib") + +using namespace std; + +// ==================== ثابت‌های بازی ==================== +const int BOARD_WIDTH = 51; +const int BOARD_HEIGHT = 25; +const int BRICK_ROWS = 5; +const int BRICK_COLS = 10; +const float BALL_SPEED = 0.5f; +const float PADDLE_SPEED = 4.0f; +const int MAX_POWERUPS = 10; +const float POWERUP_SPEED = 0.2f; +const float MIN_PADDLE_WIDTH = 2.0f; +const float MAX_PADDLE_WIDTH = 20.0f; +const float PADDLE_CHANGE = 2.0f; +const float INITIAL_PADDLE_Y = BOARD_HEIGHT - 2.0f; +const float INITIAL_PADDLE_X = BOARD_WIDTH / 2.0f - 5.0f; +const float INITIAL_BALL_X = INITIAL_PADDLE_X + 5.0f; +const float INITIAL_BALL_Y = INITIAL_PADDLE_Y - 0.5f; + +// حالت‌های بازی +const int GAME_MODE_SIMPLE = 0; +const int GAME_MODE_ADVANCED = 1; + +// انواع پاورآپ +const int POWERUP_BOMB = 0; +const int POWERUP_HEART = 1; + +// ==================== رنگ‌های ANSI ==================== +const string RESET = "\033[0m"; +const string BOLD = "\033[1m"; +const string BLUE = "\033[34m"; +const string RED = "\033[31m"; +const string WHITE = "\033[37m"; +const string GOLD = "\033[93m"; +const string YELLOW = "\033[33m"; +const string GREEN = "\033[32m"; +const string MAGENTA = "\033[35m"; +const string CYAN = "\033[36m"; +const string BRIGHT_RED = "\033[91m"; +const string BRIGHT_GREEN = "\033[92m"; +const string BRIGHT_YELLOW = "\033[93m"; +const string BRIGHT_BLUE = "\033[94m"; +const string BRIGHT_MAGENTA = "\033[95m"; +const string BRIGHT_CYAN = "\033[96m"; +const string PURPLE = "\033[38;5;129m"; +const string ORANGE = "\033[38;5;208m"; +const string PINK = "\033[38;5;201m"; +const string BROWN = "\033[38;5;94m"; + +// رنگ‌های آجرها +const string BRICK_COLOR_RED = "\033[38;5;196m"; +const string BRICK_COLOR_ORANGE = "\033[38;5;208m"; +const string BRICK_COLOR_YELLOW = "\033[38;5;226m"; +const string BRICK_COLOR_GREEN = "\033[38;5;46m"; +const string BRICK_COLOR_BLUE = "\033[38;5;27m"; +const string BRICK_COLOR_PURPLE = "\033[38;5;129m"; +const string BRICK_COLOR_PINK = "\033[38;5;201m"; +const string BRICK_COLOR_CYAN = "\033[38;5;51m"; + +// ==================== ساختارهای بازی ==================== +struct Ball +{ + float x, y; + float vx, vy; + float radius; +}; + +struct Paddle +{ + float x, y; + float width, height; + float speed; +}; + +struct Brick +{ + float x, y; + float width, height; + bool visible; +}; + +struct Powerup +{ + float x, y; + float vy; + int type; + bool active; + bool collected; +}; + +struct GameRecord +{ + string playerName; + string score; + string gameModeStr; + string result; + string Date; + string Time; +}; + +// ==================== متغیرهای سراسری ==================== +Ball ball; +Paddle paddle; +Brick bricks[BRICK_ROWS][BRICK_COLS]; +Powerup powerups[MAX_POWERUPS]; +int score = 0; +int lives = 3; +int gameMode = GAME_MODE_SIMPLE; +bool gameOver = false; +bool gameStarted = false; +bool isPaused = false; +string currentPlayerName = ""; +vector screenBuffer; + +// ==================== متغیرهای منو ==================== +int currentOption = 0; +int currentSettingsOption = 0; +int currentHelpOption = 0; +int currentBallOption = 0; +int currentPaddleOption = 0; +string selectedBallType = "●"; +string selectedPaddleType = "■"; +bool inBallSettings = false; +bool inPaddleSettings = false; + +// ==================== آرایه‌های منو ==================== +string mainMenuOptions[] = {"NEW GAME", "LOAD GAME", "HELP", "GAME HISTORY", "SETTINGS", "EXIT"}; +string pauseMenuOptions[] = {"RESUME", "RESTART", "MENU"}; +string settingsOptions[] = {"BALL TYPE", "PADDLE TYPE", "BACK TO MENU"}; +string helpOptions[] = {"CONTROLS", "ABOUT GAME", "BACK TO MENU"}; +string ballTypes[] = {"◉", "✿", "✪", "✷", "✯", "✧", "●", "◍"}; +string paddleTypes[] = {"✷", "❥", "▼", "▽", "□", "■", "◗", "●"}; + +// ==================== متغیرهای صدا ==================== +bool soundsLoaded = false; + +// ==================== اعلان توابع مدیریت صدا ==================== +void preloadSounds(); +void playSound(const string &filename); +void playBrickSound(); +void playWallSound(); +void playVictorySound(); +void playGameOverSound(); +void playLoseBallSound(); + +// ==================== اعلان توابع اصلی بازی ==================== +void runGame(); +void newGame(); +void loadGame(); +void saveGame(); +void clearSavedGame(); +void initializeBricks(); +void resetBallAndPaddle(); +void updateBall(float deltaTime); +void checkPaddleCollision(); +void checkBrickCollision(); +void checkWallCollision(); +void activatePowerUps(float deltaTime); +void powerUp(float x, float y); + +// ==================== اعلان توابع رندر و نمایش ==================== +void initScreenBuffer(); +void clearScreenBuffer(); +void renderToBuffer(); +void renderWithColorsOptimized(); +void setCursorPosition(int x, int y); +void hideCursor(); +void clearMenuArea(); +// ==================== اعلان توابع منو ==================== +void printMenu(); +void menuMove(); +void pauseMenu(); +void pauseMove(); +void resume(); +void restart(); +void showSettings(); +void settingsMove(); +void showBallSettings(); +void ballSettingsMove(); +void showPaddleSettings(); +void paddleSettingsMove(); +void selectGameMode(); +void printLoading(); +void showHelp(); +void helpMove(); +void aboutGame(); +void controls(); + +// ==================== اعلان توابع UI و گرافیک ==================== +void printVictory(); +void printGameOver(); +void printExit(int selected); +void exitMove(); +void showGameHistory(); +void saveGameHistory(const string &result); + +// ==================== اعلان توابع تنظیمات ==================== +void saveSettings(); +void loadSettings(); + +// ==================== توابع مدیریت صدا ==================== +void preloadSounds() +{ + if (soundsLoaded) + return; + + string sounds[] = { + "brick.wav", + "wall.wav", + "loseball.wav", + "Victory.wav", + "GameOver.wav"}; + + for (int i = 0; i < 5; i++) + { + PlaySound(sounds[i].c_str(), NULL, SND_FILENAME | SND_ASYNC | SND_NOSTOP); + Sleep(20); + } + + PlaySound(NULL, NULL, 0); + soundsLoaded = true; +} + +void playSound(const string &filename) +{ + PlaySound(filename.c_str(), NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT); +} + +void playBrickSound() { playSound("brick.wav"); } +void playWallSound() { playSound("wall.wav"); } +void playVictorySound() { playSound("Victory.wav"); } +void playGameOverSound() { playSound("GameOver.wav"); } +void playLoseBallSound() { playSound("loseball.wav"); } + +// ==================== توابع اصلی بازی ==================== +void initializeBricks() +{ + for (int i = 0; i < BRICK_ROWS; i++) + { + for (int j = 0; j < BRICK_COLS; j++) + { + bricks[i][j].x = 1.0f + j * 5.0f; // فاصله افقی آجرها + bricks[i][j].y = 1.0f + i * 2.0f; // فاصله عمودی آجرها + bricks[i][j].width = 4.0f; + bricks[i][j].height = 1.0f; + bricks[i][j].visible = true; + } + } +} + +void resetBallAndPaddle() +{ + paddle.x = INITIAL_PADDLE_X; + paddle.y = INITIAL_PADDLE_Y; + + ball.x = INITIAL_BALL_X; + ball.y = INITIAL_BALL_Y; + ball.vx = BALL_SPEED; + ball.vy = -BALL_SPEED; +} + +void updateBall(float deltaTime) +{ + ball.x += ball.vx * deltaTime * 15.0f; // 15 ضریب برای بهتر شدن سرعت در کنسول + ball.y += ball.vy * deltaTime * 15.0f; + + float maxSpeed = BALL_SPEED * 2.0f; + float currentSpeed = sqrt(ball.vx * ball.vx + ball.vy * ball.vy); + + // ایجاد محدودیت برای سرعت توپ به منظور کنترل بهتر + if (currentSpeed > maxSpeed) + { + float scale = maxSpeed / currentSpeed; + ball.vx *= scale; + ball.vy *= scale; + } + + float minSpeed = BALL_SPEED * 0.8f; + if (currentSpeed < minSpeed && currentSpeed > 0) + { + float scale = minSpeed / currentSpeed; + ball.vx *= scale; + ball.vy *= scale; + } +} + +void checkPaddleCollision() +{ + bool isInVerticalRange = (ball.y + ball.radius >= paddle.y) && + (ball.y - ball.radius <= paddle.y + paddle.height); + bool isInHorizontalRange = (ball.x >= paddle.x) && + (ball.x <= paddle.x + paddle.width); + + if (isInVerticalRange && isInHorizontalRange) + { + float relativeHitPoint = (ball.x - paddle.x) / paddle.width; + + const float MAX_ANGLE = 0.7854f; // 45 درجه + float angle = (relativeHitPoint - 0.5f) * MAX_ANGLE * 2.0f; + + float totalSpeed = sqrt(ball.vx * ball.vx + ball.vy * ball.vy); + + if (totalSpeed < BALL_SPEED) + { + totalSpeed = BALL_SPEED; + } + + ball.vx = totalSpeed * sin(angle); + ball.vy = -abs(totalSpeed * cos(angle)); + ball.y = paddle.y - ball.radius - 0.1f; + + playWallSound(); + } +} + +void checkBrickCollision() +{ + for (int i = 0; i < BRICK_ROWS; i++) + { + for (int j = 0; j < BRICK_COLS; j++) + { + if (!bricks[i][j].visible) + continue; + + Brick &brick = bricks[i][j]; + + bool overlapX = (ball.x + ball.radius >= brick.x) && + (ball.x - ball.radius <= brick.x + brick.width); + bool overlapY = (ball.y + ball.radius >= brick.y) && + (ball.y - ball.radius <= brick.y + brick.height); + + if (overlapX && overlapY) + { + brick.visible = false; + score += 10; + + playBrickSound(); + + if (gameMode == GAME_MODE_ADVANCED && (rand() % 100) < 70) // احتمال 70 درصد + { + // ایجاد پاورآپ + for (int k = 0; k < MAX_POWERUPS; k++) + { + if (!powerups[k].active) + { + powerups[k].x = brick.x + brick.width / 2; + powerups[k].y = brick.y + brick.height / 2; + powerups[k].vy = POWERUP_SPEED; + powerups[k].type = rand() % 2; // بمب یا قلب + powerups[k].active = true; + powerups[k].collected = false; + break; + } + } + } + + // بررسی عمق و جهت برخورد توپ با آجر + float overlapLeft = (ball.x + ball.radius) - brick.x; + float overlapRight = (brick.x + brick.width) - (ball.x - ball.radius); + float overlapTop = (ball.y + ball.radius) - brick.y; + float overlapBottom = (brick.y + brick.height) - (ball.y - ball.radius); + float minOverlapX = min(overlapLeft, overlapRight); + float minOverlapY = min(overlapTop, overlapBottom); + + if (minOverlapX < minOverlapY) + { + ball.vx = -ball.vx; + if (overlapLeft < overlapRight) + { + ball.x = brick.x - ball.radius - 0.1f; // 0.1 برای ایجاد فاصله بین توپ و آجر و جلوگیری از همپوشانی آنها در فریم بعدی + } + else + { + ball.x = brick.x + brick.width + ball.radius + 0.1f; + } + } + else + { + ball.vy = -ball.vy; + if (overlapTop < overlapBottom) + { + ball.y = brick.y - ball.radius - 0.1f; + } + else + { + ball.y = brick.y + brick.height + ball.radius + 0.1f; + } + } + + float speedIncrease = 1.01f; + ball.vx *= speedIncrease; + ball.vy *= speedIncrease; + } + } + } +} + +void checkWallCollision() +{ + // دیوار چپ + if (ball.x - ball.radius <= 1.0f) + { + ball.vx = abs(ball.vx); + ball.x = 1.0f + ball.radius + 0.1f; + playWallSound(); + } + // دیوار راست + if (ball.x + ball.radius >= BOARD_WIDTH - 1.0f) + { + ball.vx = -abs(ball.vx); + ball.x = BOARD_WIDTH - 1.0f - ball.radius - 0.1f; + playWallSound(); + } + // دیوار بالا + if (ball.y - ball.radius <= 1.0f) + { + ball.vy = abs(ball.vy); + ball.y = 1.0f + ball.radius + 0.1f; + playWallSound(); + } + // دیوار پایین + if (ball.y > BOARD_HEIGHT) + { + lives--; + playLoseBallSound(); + if (lives > 0) + { + resetBallAndPaddle(); + gameStarted = false; + } + else + { + gameOver = true; + } + } +} + +void activatePowerUps(float deltaTime) +{ + for (int i = 0; i < MAX_POWERUPS; i++) + { + if (powerups[i].active && !powerups[i].collected) + { + powerups[i].y += powerups[i].vy; + + bool hitPaddle = (powerups[i].y >= paddle.y) && + (powerups[i].y <= paddle.y + paddle.height) && + (powerups[i].x >= paddle.x) && + (powerups[i].x <= paddle.x + paddle.width); + + if (hitPaddle) + { + powerups[i].collected = true; + + if (powerups[i].type == POWERUP_BOMB) + { + paddle.width = max(MIN_PADDLE_WIDTH, paddle.width - PADDLE_CHANGE); // برای کنترل طول راکت محدوده ای در نظر گرفته شده + } + else if (powerups[i].type == POWERUP_HEART) + { + paddle.width = min(MAX_PADDLE_WIDTH, paddle.width + PADDLE_CHANGE); + } + } + if (powerups[i].y > BOARD_HEIGHT) + { + powerups[i].active = false; + } + } + } +} + +// ==================== توابع رندر ==================== +void initScreenBuffer() +{ + screenBuffer.resize(BOARD_HEIGHT + 3); + for (int i = 0; i < screenBuffer.size(); i++) + { + screenBuffer[i].resize(BOARD_WIDTH, ' '); + } +} + +void clearScreenBuffer() +{ + for (int i = 0; i < screenBuffer.size(); i++) + { + for (int j = 0; j < BOARD_WIDTH; j++) + { + screenBuffer[i][j] = ' '; + } + } +} + +void setCursorPosition(int x, int y) +{ + COORD coord; + coord.X = x; + coord.Y = y; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); +} + +void hideCursor() +{ + CONSOLE_CURSOR_INFO cursorInfo; + GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursorInfo); + cursorInfo.bVisible = false; + SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursorInfo); +} + +void renderToBuffer() +{ + clearScreenBuffer(); + + // کادر + for (int i = 0; i < BOARD_WIDTH; i++) + { + screenBuffer[0][i] = '-'; + screenBuffer[BOARD_HEIGHT - 1][i] = '-'; + } + + for (int i = 1; i < BOARD_HEIGHT - 1; i++) + { + screenBuffer[i][0] = '|'; + screenBuffer[i][BOARD_WIDTH - 1] = '|'; + } + + // راکت + int paddleYPos = (int)paddle.y; + if (paddleYPos >= 0 && paddleYPos < BOARD_HEIGHT) + { + int paddleStart = max(1, (int)paddle.x); + int paddleEnd = min(BOARD_WIDTH - 2, (int)(paddle.x + paddle.width)); + + for (int i = paddleStart; i <= paddleEnd; i++) + { + if (i >= 1 && i < BOARD_WIDTH - 1) + { + screenBuffer[paddleYPos][i] = '='; + } + } + } + + // توپ + int ballX = (int)ball.x; + int ballY = (int)ball.y; + if (ballX >= 1 && ballX < BOARD_WIDTH - 1 && ballY >= 1 && ballY < BOARD_HEIGHT - 1) + { + screenBuffer[ballY][ballX] = 'O'; + } + + // آجرها + for (int i = 0; i < BRICK_ROWS; i++) + { + for (int j = 0; j < BRICK_COLS; j++) + { + if (bricks[i][j].visible) + { + int brickX = (int)bricks[i][j].x; + int brickY = (int)bricks[i][j].y; + int brickWidth = (int)bricks[i][j].width; + + brickX = max(1, brickX); + brickY = max(1, brickY); + + for (int k = 0; k < brickWidth && brickX + k < BOARD_WIDTH - 1; k++) + { + if (brickY >= 1 && brickY < BOARD_HEIGHT - 1) + { + screenBuffer[brickY][brickX + k] = 'B'; + } + } + } + } + } + + // پاورآپ‌ها + if (gameMode == GAME_MODE_ADVANCED) + { + for (int i = 0; i < MAX_POWERUPS; i++) + { + if (powerups[i].active && !powerups[i].collected) + { + int px = (int)powerups[i].x; + int py = (int)powerups[i].y; + + if (px >= 1 && px < BOARD_WIDTH - 1 && py >= 1 && py < BOARD_HEIGHT - 1) + { + if (powerups[i].type == POWERUP_BOMB) + { + screenBuffer[py][px] = 'X'; + } + else + { + screenBuffer[py][px] = '+'; + } + } + } + } + } +} + +void renderWithColorsOptimized() +{ + if (!isPaused) + { + setCursorPosition(0, 0); + } + + string fullFrame; + fullFrame.reserve(BOARD_HEIGHT * (BOARD_WIDTH + 20)); + + for (int i = 0; i < BOARD_HEIGHT; i++) + { + if (i < screenBuffer.size()) + { + for (int j = 0; j < BOARD_WIDTH; j++) + { + char ch = screenBuffer[i][j]; + + if (ch == 'B') + { + bool isBrick = false; + int brickRow = -1, brickCol = -1; + + for (int r = 0; r < BRICK_ROWS; r++) + { + bool foundInThisRow = false; + for (int c = 0; c < BRICK_COLS; c++) + { + if (bricks[r][c].visible) + { + int brickX = (int)bricks[r][c].x; + int brickY = (int)bricks[r][c].y; + int brickWidth = (int)bricks[r][c].width; + + if (i == brickY && j >= brickX && j < brickX + brickWidth) + { + isBrick = true; + brickRow = r; + brickCol = c; + foundInThisRow = true; + break; + } + } + } + if (foundInThisRow) + break; + } + + if (isBrick) + { + int colorIndex = (brickRow * BRICK_COLS + brickCol) % 8; + + switch (colorIndex) + { + case 0: + fullFrame += BRICK_COLOR_RED; + break; + case 1: + fullFrame += BRICK_COLOR_ORANGE; + break; + case 2: + fullFrame += BRICK_COLOR_YELLOW; + break; + case 3: + fullFrame += BRICK_COLOR_GREEN; + break; + case 4: + fullFrame += BRICK_COLOR_BLUE; + break; + case 5: + fullFrame += BRICK_COLOR_PURPLE; + break; + case 6: + fullFrame += BRICK_COLOR_PINK; + break; + case 7: + fullFrame += BRICK_COLOR_CYAN; + break; + } + fullFrame += "█"; + fullFrame += RESET; + } + else + { + fullFrame += ' '; + } + } + else if (ch == '=') + { + fullFrame += CYAN; + fullFrame += selectedPaddleType; + fullFrame += RESET; + } + else if (ch == 'O') + { + fullFrame += GOLD; + fullFrame += selectedBallType; + fullFrame += RESET; + } + else if (ch == 'X') + { + fullFrame += RED; + fullFrame += "⊙"; + fullFrame += RESET; + } + else if (ch == '+') + { + fullFrame += PINK; + fullFrame += "♡"; + fullFrame += RESET; + } + else + { + fullFrame += ch; + } + } + } + fullFrame += '\n'; + } + + cout << fullFrame; + + // اطلاعات بازی + if (!isPaused) + { + cout << "Player: " << BRIGHT_CYAN << currentPlayerName << RESET << " | "; + cout << "Score: " << BRIGHT_YELLOW << score << RESET << endl; + cout << "Lives: " << BRIGHT_RED; + for (int i = 0; i < lives; i++) + cout << "❤️"; + cout << RESET; + + cout << " | Mode: " << (gameMode == GAME_MODE_SIMPLE ? PINK : BRIGHT_MAGENTA) + << (gameMode == GAME_MODE_SIMPLE ? "Simple " : "Advanced ") << RESET; + + cout << endl; + if (!gameStarted && !gameOver) + { + cout << BRIGHT_GREEN << "Press SPACE to start or continue the game " << RESET; + cout << endl; + } + else + { + cout << CYAN << "Use A/D to move paddle, P to pause " << RESET; + cout << endl; + } + } +} +// ==================== تابع کمکی برای منوها ==================== +void clearMenuArea() +{ + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(hConsole, &csbi); + + COORD topLeft = {0, 0}; + DWORD written; + DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y; + + FillConsoleOutputCharacter(hConsole, ' ', cellCount, topLeft, &written); + FillConsoleOutputAttribute(hConsole, csbi.wAttributes, cellCount, topLeft, &written); + SetConsoleCursorPosition(hConsole, topLeft); +} + +// ==================== توابع منو ==================== +void printMenu() +{ + COORD pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + + cout << "\n\n\n\n"; + cout << " ╔════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗"; + cout << "\n\n\n\n"; + cout << " ██████╗ ██████╗ ███████╗ █████╗ ██╗ ██╗ ██████╗ ██╗ ██╗ ████████╗\n"; + cout << " ██╔══██╗ ██╔══██╗ ██╔════╝ ██╔══██╗ ██║ ██╔╝ ██╔═══██╗ ██║ ██║ ╚══██╔══╝\n"; + cout << " ██║ ██║ ██║ ██║ █████╗ ███████║ █████╔╝ ██║ ██║ ██║ ██║ ██║ \n"; + cout << " ██████╔╝ ██████╔╝ ██╔══╝ ██╔══██║ ██╔═██╗ ██║ ██║ ██║ ██║ ██║ \n"; + cout << " ██╔══██╗ ██╔══██╗ ███████╗ ██║ ██║ ██║ ██╗ ╚██████╔╝ ╚██████╔╝ ██║ \n"; + cout << " ██████╔╝ ██║ ██║ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ \n"; + cout << endl + << endl; + + int boxWidth = 18; + cout << BOLD << WHITE << " ╔════════════════════════╗" << RESET << "\n"; + + for (int i = 0; i < 6; i++) + { + string boxColor; + if (i == currentOption) + boxColor = BLUE; + else + boxColor = WHITE; + + string textColor; + if (i == currentOption) + textColor = BLUE; + else if (mainMenuOptions[i] == "EXIT") + textColor = RED; + else + textColor = WHITE; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╔"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╗" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "║ " << RESET; + if (i == currentOption) + cout << BOLD << BLUE << "➤ " << RESET; + else + cout << " "; + + cout << BOLD << textColor << mainMenuOptions[i] << " " << RESET; + cout << string(boxWidth - (mainMenuOptions[i].length() + 4), ' '); + cout << BOLD << boxColor << "║" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╚"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╝" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + } + cout << BOLD << WHITE << " ╚════════════════════════╝" << RESET << "\n\n\n"; + + cout << " ╚════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝"; + pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); +} + +void menuMove() +{ + clearMenuArea(); + printMenu(); + + int previousOption = -1; + + while (true) + { + if (previousOption != currentOption) + { + printMenu(); + previousOption = currentOption; + } + + if (_kbhit()) + { + char ch = _getch(); + if (ch == 'w' || ch == 'W') + { + if (currentOption > 0) + currentOption--; + } + else if (ch == 's' || ch == 'S') + { + if (currentOption < 5) + currentOption++; + } + else if (ch == '\r') + { + switch (currentOption) + { + case 0: + printLoading(); + newGame(); + clearMenuArea(); + printMenu(); + previousOption = -1; + break; + case 1: + clearMenuArea(); + printLoading(); + loadGame(); + clearMenuArea(); + printMenu(); + previousOption = -1; + break; + case 2: + printLoading(); + clearMenuArea(); + helpMove(); + clearMenuArea(); + printMenu(); + previousOption = -1; + break; + case 3: + printLoading(); + clearMenuArea(); + showGameHistory(); + clearMenuArea(); + printMenu(); + previousOption = -1; + break; + case 4: + printLoading(); + clearMenuArea(); + settingsMove(); + clearMenuArea(); + printMenu(); + previousOption = -1; + break; + case 5: + system("cls"); + exitMove(); + clearMenuArea(); + printMenu(); + previousOption = -1; + break; + } + } + } + Sleep(50); + } +} + +void pauseMenu() +{ + COORD pos = {40, 14}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + + string menu = BOLD + WHITE + " ╔════════════════════════╗" + RESET + "\n"; + + for (int i = 0; i < 3; i++) + { + string boxColor = (i == currentOption) ? BLUE : WHITE; + + menu += BOLD + WHITE + " ║ " + RESET; + menu += BOLD + boxColor + "╔══════════════════╗" + RESET; + menu += BOLD + WHITE + " ║" + RESET + "\n"; + + menu += BOLD + WHITE + " ║ " + RESET; + menu += BOLD + boxColor + "║ "; + if (i == currentOption) + menu += "➤ "; + else + menu += " "; + menu += pauseMenuOptions[i]; + + int totalWidth = 16; // عرض کل کادر داخلی + int usedWidth = pauseMenuOptions[i].length() + ((i == currentOption) ? 2 : 2); + int spaces = totalWidth - usedWidth; + if (spaces > 0) + menu += string(spaces, ' '); + + menu += "║" + RESET; + menu += BOLD + WHITE + " ║" + RESET + "\n"; + + menu += BOLD + WHITE + " ║ " + RESET; + menu += BOLD + boxColor + "╚══════════════════╝" + RESET; + menu += BOLD + WHITE + " ║" + RESET + "\n"; + } + menu += BOLD + WHITE + " ╚════════════════════════╝" + RESET; + cout << menu; +} + +void pauseMove() +{ + clearMenuArea(); + currentOption = 0; + + pauseMenu(); + + int previousOption = -1; + + while (isPaused) + { + if (previousOption != currentOption) + { + pauseMenu(); + previousOption = currentOption; + } + + if (_kbhit()) + { + char a = _getch(); + if (a == 'w' || a == 'W') + { + if (currentOption > 0) + currentOption--; + } + else if (a == 's' || a == 'S') + { + if (currentOption < 2) + currentOption++; + } + else if (a == '\r') + { + switch (currentOption) + { + case 0: + isPaused = false; + clearMenuArea(); + return; + case 1: + restart(); + return; + case 2: + saveGame(); + gameOver = true; + isPaused = false; + menuMove(); + return; + } + } + } + Sleep(50); + } +} + +void resume() +{ + isPaused = false; + clearMenuArea(); +} + +void restart() +{ + isPaused = false; + score = 0; + lives = 3; + gameOver = false; + gameStarted = false; + + initializeBricks(); + + paddle.x = INITIAL_PADDLE_X; + paddle.y = INITIAL_PADDLE_Y; + paddle.width = 10.0f; + paddle.height = 1.0f; + paddle.speed = PADDLE_SPEED; + + ball.x = INITIAL_BALL_X; + ball.y = INITIAL_BALL_Y; + ball.vx = BALL_SPEED; + ball.vy = -BALL_SPEED; + ball.radius = 0.5f; + + if (gameMode == GAME_MODE_ADVANCED) + { + for (int i = 0; i < MAX_POWERUPS; i++) + { + powerups[i].active = false; + powerups[i].collected = false; + } + } + + resetBallAndPaddle(); + clearMenuArea(); +} + +// ==================== توابع راهنما ==================== +void showHelp() +{ + COORD pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + + cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; + + int boxWidth = 18; + cout << BOLD << WHITE << " ╔════════════════════════╗" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ " << BOLD << BLUE << " HELP MENU" << BOLD << WHITE << " ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ╠════════════════════════╣" << RESET << "\n"; + + for (int i = 0; i < 3; i++) + { + string boxColor; + if (i == currentHelpOption) + boxColor = BLUE; + else + boxColor = WHITE; + + string textColor; + if (i == currentHelpOption) + textColor = BLUE; + else + textColor = WHITE; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╔"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╗" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "║ " << RESET; + if (i == currentHelpOption) + cout << BOLD << BLUE << "➤ " << RESET; + else + cout << " "; + + cout << BOLD << textColor << helpOptions[i] << " " << RESET; + cout << string(boxWidth - (helpOptions[i].length() + 4), ' '); + cout << BOLD << boxColor << "║" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╚"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╝" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + } + cout << BOLD << WHITE << " ╚════════════════════════╝" << RESET << "\n"; + + pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); +} + +void helpMove() +{ + currentHelpOption = 0; + clearMenuArea(); + showHelp(); + + int previousOption = -1; + + while (true) + { + if (previousOption != currentHelpOption) + { + showHelp(); + previousOption = currentHelpOption; + } + + if (_kbhit()) + { + char ch = _getch(); + if (ch == 'w' || ch == 'W') + { + if (currentHelpOption > 0) + currentHelpOption--; + } + else if (ch == 's' || ch == 'S') + { + if (currentHelpOption < 2) + currentHelpOption++; + } + else if (ch == '\r') + { + switch (currentHelpOption) + { + case 0: + controls(); + clearMenuArea(); + showHelp(); + previousOption = -1; + break; + case 1: + aboutGame(); + clearMenuArea(); + showHelp(); + previousOption = -1; + break; + case 2: + return; + } + } + else if (ch == 27) + { + return; + } + } + Sleep(50); + } +} + +void controls() +{ + system("cls"); + cout << "\n\n\n\n\n\n\n\n\n\n\n\n"; + cout << BOLD << GOLD << " ╔════════════════════════════════════════════════╗\n"; + cout << " ║ HELP ║\n"; + cout << " ╠════════════════════════════════════════════════╣\n"; + cout << " ║ ║\n"; + cout << " ║ Goal: Break all bricks with the ball ║\n"; + cout << " ║ ║\n"; + cout << " ║ Controls: ║\n"; + cout << " ║ A : Move paddle left ║\n"; + cout << " ║ D : Move paddle right ║\n"; + cout << " ║ P : Pause/Resume ║\n"; + cout << " ║ HEART : Increase length of paddle ║\n"; + cout << " ║ BOMB : Decrease length of paddle ║\n"; + cout << " ║ ║\n"; + cout << " ║ You have 3 lives. Don't let ball fall! ║\n"; + cout << " ║ ║\n"; + cout << " ╚════════════════════════════════════════════════╝\n" + << RESET; + cout << " Press any key to return..."; + _getch(); +} + +void aboutGame() +{ + system("cls"); + ifstream file("aboutgame.txt"); + if (!file.is_open()) + { + cout << RED << "Nothing has found :(" << RESET << endl; + return; + } + string line; + while (getline(file, line)) + { + cout << line << endl; + } + file.close(); + cout << endl; + cout << BOLD << BRIGHT_RED << "Press any key to return..." << RESET; + _getch(); +} + +// ==================== توابع تنظیمات ==================== +void saveSettings() +{ + ofstream file("settings.txt"); + if (file.is_open()) + { + file << selectedBallType << endl; + file << selectedPaddleType << endl; + file.close(); + } +} + +void loadSettings() +{ + ifstream file("settings.txt"); + if (file.is_open()) + { + file >> selectedBallType; + file >> selectedPaddleType; + file.close(); + } +} +void showSettings() +{ + COORD pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + + cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; + + int boxWidth = 18; + cout << BOLD << WHITE << " ╔════════════════════════╗" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ " << BOLD << BLUE << "SETTINGS MENU" << BOLD << WHITE << " ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ╠════════════════════════╣" << RESET << "\n"; + + for (int i = 0; i < 3; i++) + { + string boxColor; + if (i == currentSettingsOption) + boxColor = BLUE; + else + boxColor = WHITE; + + string textColor; + if (i == currentSettingsOption) + textColor = BLUE; + else + textColor = WHITE; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╔"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╗" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "║ " << RESET; + if (i == currentSettingsOption) + cout << BOLD << BLUE << "➤ " << RESET; + else + cout << " "; + + cout << BOLD << textColor << settingsOptions[i] << " " << RESET; + cout << string(boxWidth - (settingsOptions[i].length() + 4), ' '); + cout << BOLD << boxColor << "║" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╚"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╝" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + } + cout << BOLD << WHITE << " ╚════════════════════════╝" << RESET << "\n"; + + pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); +} + +void settingsMove() +{ + currentSettingsOption = 0; + clearMenuArea(); + showSettings(); + + int previousOption = -1; + + while (true) + { + if (previousOption != currentSettingsOption) + { + showSettings(); + previousOption = currentSettingsOption; + } + + if (_kbhit()) + { + char ch = _getch(); + if (ch == 'w' || ch == 'W') + { + if (currentSettingsOption > 0) + currentSettingsOption--; + } + else if (ch == 's' || ch == 'S') + { + if (currentSettingsOption < 2) + currentSettingsOption++; + } + else if (ch == '\r') + { + switch (currentSettingsOption) + { + case 0: + inBallSettings = true; + ballSettingsMove(); + clearMenuArea(); + showSettings(); + previousOption = -1; + break; + case 1: + inPaddleSettings = true; + paddleSettingsMove(); + clearMenuArea(); + showSettings(); + previousOption = -1; + break; + case 2: + return; + } + } + } + Sleep(50); + } +} +void showBallSettings() +{ + COORD pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + + cout << "\n\n\n\n\n"; + + int boxWidth = 25; + cout << BOLD << WHITE << " ╔═══════════════════════════════╗" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ " << BOLD << BLUE << "BALL SETTINGS" << BOLD << WHITE << " ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ╠═══════════════════════════════╣" << RESET << "\n"; + + for (int i = 0; i < 8; i++) + { + string boxColor; + if (i == currentBallOption) + boxColor = BLUE; + else + boxColor = WHITE; + + string textColor; + if (i == currentBallOption) + textColor = BLUE; + else + textColor = WHITE; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╔"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╗" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "║ " << RESET; + if (i == currentBallOption) + cout << BOLD << BLUE << "➤ " << RESET; + else + cout << " "; + + cout << BOLD << textColor << ballTypes[i] << " " << RESET; + cout << string(boxWidth - (ballTypes[i].length() + 2), ' '); + cout << BOLD << boxColor << "║" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╚"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╝" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + } + + // گزینه بازگشت + string backOption = "BACK TO SETTINGS"; + string backBoxColor = (currentBallOption == 8) ? BLUE : WHITE; + string backTextColor = (currentBallOption == 8) ? BLUE : WHITE; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << backBoxColor << "╔"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╗" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << backBoxColor << "║ " << RESET; + if (currentBallOption == 8) + cout << BOLD << BLUE << "➤ " << RESET; + else + cout << " "; + cout << BOLD << backTextColor << backOption << " " << RESET; + cout << string(boxWidth - (backOption.length() + 4), ' '); + cout << BOLD << backBoxColor << "║" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << backBoxColor << "╚"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╝" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ╚═══════════════════════════════╝" << RESET << "\n"; + + pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); +} + +void ballSettingsMove() +{ + int previousOption = -1; + clearMenuArea(); + showBallSettings(); + + while (inBallSettings) + { + if (previousOption != currentBallOption) + { + showBallSettings(); + previousOption = currentBallOption; + } + + if (_kbhit()) + { + char ch = _getch(); + if (ch == 'w' || ch == 'W') + { + if (currentBallOption > 0) + currentBallOption--; + } + else if (ch == 's' || ch == 'S') + { + if (currentBallOption < 8) + currentBallOption++; + } + else if (ch == '\r') + { + if (currentBallOption == 8) + { + inBallSettings = false; + } + else + { + selectedBallType = ballTypes[currentBallOption]; + saveSettings(); + + system("cls"); + COORD pos = {0, 20}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + + cout << BOLD << WHITE << " ╔════════════════════════╗" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ " << BOLD << GREEN << "SETTING SAVED!" << BOLD << WHITE << " ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ╚════════════════════════╝" << RESET << "\n"; + + this_thread::sleep_for(chrono::seconds(2)); + clearMenuArea(); + showBallSettings(); + previousOption = -1; + } + } + } + Sleep(50); + } +} + +void showPaddleSettings() +{ + COORD pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + + cout << "\n\n\n\n\n"; + + int boxWidth = 27; + cout << BOLD << WHITE << " ╔═════════════════════════════════╗" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ " << BOLD << BLUE << "PADDLE SETTINGS" << BOLD << WHITE << " ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ╠═════════════════════════════════╣" << RESET << "\n"; + + for (int i = 0; i < 8; i++) + { + string boxColor; + if (i == currentPaddleOption) + boxColor = BLUE; + else + boxColor = WHITE; + + string textColor; + if (i == currentPaddleOption) + textColor = BLUE; + else + textColor = WHITE; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╔"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╗" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "║ " << RESET; + if (i == currentPaddleOption) + cout << BOLD << BLUE << "➤ " << RESET; + else + cout << " "; + + cout << BOLD << textColor << paddleTypes[i] << " " << RESET; + cout << string(boxWidth - (paddleTypes[i].length() + 2), ' '); + cout << BOLD << boxColor << "║" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╚"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╝" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + } + + // گزینه بازگشت + string backOption = "BACK TO SETTINGS"; + string backBoxColor = (currentPaddleOption == 8) ? BLUE : WHITE; + string backTextColor = (currentPaddleOption == 8) ? BLUE : WHITE; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << backBoxColor << "╔"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╗" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << backBoxColor << "║ " << RESET; + if (currentPaddleOption == 8) + cout << BOLD << BLUE << "➤ " << RESET; + else + cout << " "; + cout << BOLD << backTextColor << backOption << " " << RESET; + cout << string(boxWidth - (backOption.length() + 4), ' '); + cout << BOLD << backBoxColor << "║" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << backBoxColor << "╚"; + for (int j = 0; j < boxWidth; j++) + cout << "═"; + cout << "╝" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ╚═════════════════════════════════╝" << RESET << "\n"; + + pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); +} + +void paddleSettingsMove() +{ + int previousOption = -1; + clearMenuArea(); + showPaddleSettings(); + + while (inPaddleSettings) + { + if (previousOption != currentPaddleOption) + { + showPaddleSettings(); + previousOption = currentPaddleOption; + } + + if (_kbhit()) + { + char ch = _getch(); + if (ch == 'w' || ch == 'W') + { + if (currentPaddleOption > 0) + currentPaddleOption--; + } + else if (ch == 's' || ch == 'S') + { + if (currentPaddleOption < 8) + currentPaddleOption++; + } + else if (ch == '\r') + { + if (currentPaddleOption == 8) + { + inPaddleSettings = false; + break; + } + else + { + selectedPaddleType = paddleTypes[currentPaddleOption]; + saveSettings(); + + system("cls"); + COORD pos = {0, 20}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + + cout << BOLD << WHITE << " ╔════════════════════════╗" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ " << BOLD << GREEN << "SETTING SAVED!" << BOLD << WHITE << " ║" << RESET << "\n"; + cout << BOLD << WHITE << " ║ ║" << RESET << "\n"; + cout << BOLD << WHITE << " ╚════════════════════════╝" << RESET << "\n"; + + this_thread::sleep_for(chrono::seconds(2)); + clearMenuArea(); + showPaddleSettings(); + previousOption = -1; + } + } + else if (ch == 27) + { + inPaddleSettings = false; + break; + } + } + Sleep(50); + } +} + +// ==================== توابع UI ==================== +void printVictory() +{ + system("cls"); + cout << "\n\n\n\n\n\n\n\n\n\n\n\n"; + playVictorySound(); + cout << GOLD; + cout << " ██╗ ██╗ ██╗ ██████╗ ████████╗ ██████╗ ██████╗ ██╗ ██╗\n"; + cout << " ██║ ██║ ██║ ██╔════╝ ╚══██╔══╝ ██╔═══██╗ ██╔══██╗ ╚██╗ ██╔╝\n"; + cout << " ██║ ██║ ██║ ██║ ██║ ██║ ██║ ██████╔╝ ╚████╔╝ \n"; + cout << " ╚██╗ ██╔╝ ██║ ██║ ██║ ██║ ██║ ██╔══██╗ ╚██╔╝ \n"; + cout << " ╚████╔╝ ██║ ╚██████╗ ██║ ╚██████╔╝ ██║ ██║ ██║ \n"; + cout << " ╚═══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ \n\n"; + cout << " ██╗██████████████████╔██\n"; + cout << " ╚═╝ ████████████████ ╚═╝\n"; + cout << " ██████████████\n"; + cout << " ████████████\n"; + cout << " ██████████\n"; + cout << " ████████\n"; + cout << " ██████\n"; + cout << " ████\n"; + cout << " ██\n"; + cout << " ██\n"; + cout << " ████████\n"; + cout << " ████████\n"; + cout << RESET; + Sleep(2000); +} + +void printGameOver() +{ + system("cls"); + playGameOverSound(); + cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; + cout << RED; + cout << " ██████╗ █████╗ ███╗ ███╗ ███████╗ ██████╗ ██╗ ██╗ ███████╗ ██████╗ \n"; + cout << " ██╔════╝ ██╔══██╗ ████╗ ████║ ██╔════╝ ██╔═══██╗ ██║ ██║ ██╔════╝ ██╔══██╗\n"; + cout << " ██║ ███╗ ███████║ ██╔████╔██║ █████╗ ██║ ██║ ██║ ██║ █████╗ ██████\n"; + cout << " ██║ ██║ ██╔══██║ ██║╚██╔╝██║ ██╔══╝ ██║ ██║ ╚██╗ ██╔╝ ██╔══╝ ██╔══██╗\n"; + cout << " ╚██████╔╝ ██║ ██║ ██║ ╚═╝ ██║ ███████╗ ╚██████╔╝ ╚████╔╝ ███████╗ ██║ ██║\n"; + cout << " ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═══╝ ╚══════╝ ╚═╝ ╚═╝\n"; + cout << RESET; + Sleep(2000); +} + +void printExit(int selected) +{ + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + COORD topLeft = {51, 18}; // موقعیت وسط صفحه + DWORD written; + + // پاک کردن 5 خط + for (int i = 0; i < 5; i++) + { + FillConsoleOutputCharacter(hConsole, ' ', 50, topLeft, &written); + topLeft.Y++; + } + + // رفتن به موقعیت شروع + COORD pos = {51, 18}; + SetConsoleCursorPosition(hConsole, pos); + + cout << BOLD << " ╔════════════════════════════════════════╗" << endl; + + // رفتن به خط دوم + pos.Y++; + SetConsoleCursorPosition(hConsole, pos); + cout << " ║" << RED << " Are you sure you want to quit? " << RESET << BOLD << " ║" << endl; + + // رفتن به خط سوم + pos.Y++; + SetConsoleCursorPosition(hConsole, pos); + cout << " ╠═══════════════════╦════════════════════╣" << endl; + + // رفتن به خط چهارم + pos.Y++; + SetConsoleCursorPosition(hConsole, pos); + + // کل خط چهارم رو یکجا چاپ کن + cout << " ║"; + if (selected == 0) + { + cout << BLUE << BOLD << " ➤ YES " << RESET << BOLD; + } + else + { + cout << " YES "; + } + cout << "║"; + + if (selected == 1) + { + cout << BLUE << BOLD << " ➤ NO " << RESET << BOLD; + } + else + { + cout << " NO "; + } + cout << "║" << endl; + + // رفتن به خط پنجم + pos.Y++; + SetConsoleCursorPosition(hConsole, pos); + cout << " ╚═══════════════════╩════════════════════╝" << RESET; + + // برگرداندن مکان‌نما به ابتدای منو + pos.X = 51; + pos.Y = 18; + SetConsoleCursorPosition(hConsole, pos); +} + +void exitMove() +{ + int selected = 0; + printExit(selected); + while (true) + { + // فقط وقتی که گزینه تغییر کرده + static int lastSelected = -1; + if (lastSelected != selected) + { + // فقط خط چهارم رو به‌روز کن (جایی که YES/NO هست) + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + COORD pos = {51, 21}; // خط چهارم + SetConsoleCursorPosition(hConsole, pos); + + // خط چهارم رو دوباره بکش + cout << " ║"; + if (selected == 0) + { + cout << BLUE << BOLD << " YES " << RESET << BOLD; + } + else + { + cout << " YES "; + } + cout << "║"; + + if (selected == 1) + { + cout << BLUE << BOLD << " NO " << RESET << BOLD; + } + else + { + cout << " NO "; + } + cout << "║"; + + // فضای اضافی رو پاک کن + cout << " "; + + // برگرد به موقعیت + pos.X = 51; + pos.Y = 21; + SetConsoleCursorPosition(hConsole, pos); + + lastSelected = selected; + } + + if (_kbhit()) + { + char a = _getch(); + if (a == 'a' || a == 'A') + { + selected = 0; + } + else if (a == 'd' || a == 'D') + { + selected = 1; + } + else if (a == '\r') + { + if (selected == 0) + { + clearMenuArea(); + exit(0); + } + else + { + return; + } + } + } + Sleep(50); + } +} + +void printLoading() +{ + system("cls"); + hideCursor(); + cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; + cout << " ██╗ " << " ██████╗ " << " █████╗ " << " ██████╗ " << " ██╗" << " ███╗ ██╗" << " ██████╗ \n"; + cout << " ██║ " << " ██╔═══██╗" << " ██╔══██╗ " << " ██╔══██╗ " << " ██║" << " ████╗ ██║" << " ██ \n"; + cout << " ██║ " << " ██║ ██║" << " ███████║ " << " ██║ ██║ " << " ██║" << " ██╔██╗ ██║" << " ██║ ███║\n"; + cout << " ██║ " << " ██║ ██║" << " ██╔══██║ " << " ██║ ██║ " << " ██║" << " ██║╚██╗██║" << " ██║ ██║\n"; + cout << " ███████╗" << " ╚██████╔╝" << " ██║ ██║ " << " ██████╔╝ " << " ██║" << " ██║ ╚████║" << " ╚██████╔╝\n"; + cout << " ╚══════╝" << " ╚═════╝ " << " ╚═╝ ╚═╝ " << " ╚═════╝ " << " ╚═╝" << " ╚═╝ ╚═══╝" << " ╚═════╝ \n\n"; + + string spinner = "|/-\\"; + for (int i = 0; i < 30; i++) + { + cout << BOLD << WHITE << "\r LOADING " << spinner[i % spinner.size()] << flush; + this_thread::sleep_for(chrono::milliseconds(200)); + } +} +void selectGameMode() +{ + string modes[] = {"SIMPLE GAME", "ADVANCED GAME"}; + int selectedMode = 0; + int previousMode = -1; + + clearMenuArea(); + + while (true) + { + if (previousMode != selectedMode) + { + COORD pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + + cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; + cout << BOLD << WHITE << " ╔════════════════════════╗" << RESET << "\n"; + + for (int i = 0; i < 2; i++) + { + string boxColor = (i == selectedMode) ? BLUE : WHITE; + string textColor = (i == selectedMode) ? BLUE : WHITE; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╔══════════════════╗" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "║ " << RESET; + + if (i == selectedMode) + { + cout << BOLD << BLUE << "➤ " << RESET; + } + else + { + cout << " "; + } + + cout << BOLD << textColor << modes[i] << RESET; + cout << string(15 - modes[i].length(), ' '); + cout << BOLD << boxColor << "║" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + + cout << BOLD << WHITE << " ║ " << RESET; + cout << BOLD << boxColor << "╚══════════════════╝" << RESET; + cout << BOLD << WHITE << " ║" << RESET << "\n"; + } + cout << BOLD << WHITE << " ╚════════════════════════╝" << RESET << "\n"; + + pos = {0, 0}; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); + + previousMode = selectedMode; + } + + if (_kbhit()) + { + char ch = _getch(); + if (ch == 'w' || ch == 'W') + { + if (selectedMode > 0) + selectedMode--; + } + else if (ch == 's' || ch == 'S') + { + if (selectedMode < 1) + selectedMode++; + } + else if (ch == '\r') + { + gameMode = selectedMode; + return; + } + } + Sleep(50); + } +} +// ==================== توابع تاریخچه بازی ==================== +void saveGameHistory(const string &result) +{ + ofstream file("gameHistory.txt", ios::app); + time_t now = time(0); + tm *ltm = localtime(&now); + string date = to_string(1900 + ltm->tm_year) + "-" + + to_string(1 + ltm->tm_mon) + "-" + + to_string(ltm->tm_mday); + + string time = to_string(ltm->tm_hour) + ":" + + to_string(ltm->tm_min) + ":" + + to_string(ltm->tm_sec); + + string gameModeStr = (gameMode == GAME_MODE_SIMPLE ? "Simple" : "Advanced"); + + file << currentPlayerName << endl; + file << gameModeStr << endl; + file << score << endl; + file << result << endl; + file << date << endl; + file << time << endl; + file.close(); +} + +void showGameHistory() +{ + ifstream file("gameHistory.txt"); + if (!file.is_open()) + { + cout << RED << "Nothing has found :(" << RESET << endl; + cout << "\n\n"; + return; + } + + GameRecord histories[1000]; + int count = 0; + + while (count < 1000 && + (file >> histories[count].playerName >> + histories[count].gameModeStr >> + histories[count].score >> + histories[count].result >> + histories[count].Date >> + histories[count].Time)) + { + count++; + } + file.close(); + + if (count == 0) + { + cout << "\033[1;31mNo history found.\033[0m" << endl; + return; + } + + cout << " ╔════════════════╦════════════════╦════════════════╦════════════════╦════════════════╦════════════════╗" << endl; + cout << " ║ Name ║ Mode ║ score ║ result ║ Date ║ Time ║ " << endl; + cout << " ╠════════════════╬════════════════╬════════════════╬════════════════╬════════════════╬════════════════╣" << endl; + + for (int i = 0; i < count; i++) + { + cout << " ║ " << histories[i].playerName << string(15 - histories[i].playerName.size(), ' ') + << "║ " << histories[i].gameModeStr << string(15 - histories[i].gameModeStr.size(), ' ') + << "║ " << histories[i].score << string(15 - histories[i].score.size(), ' ') + << "║ " << histories[i].result << string(15 - histories[i].result.size(), ' ') + << "║ " << histories[i].Date << string(15 - histories[i].Date.size(), ' ') + << "║ " << histories[i].Time << string(15 - histories[i].Time.size(), ' ') + << "║" << endl; + + if (i != count - 1) + { + cout << " ╠════════════════╬════════════════╬════════════════╬════════════════╬════════════════╬════════════════╣" << endl; + } + } + cout << " ╚════════════════╩════════════════╩════════════════╩════════════════╩════════════════╩════════════════╝" << endl; + cout << " Press any key to return to main menu ..."; + _getch(); +} + +// ==================== توابع ذخیره و بارگذاری ==================== +void saveGame() +{ + ofstream file("saved_game.txt"); + if (file.is_open()) + { + file << gameMode << endl; + file << ball.x << " " << ball.y << " " << ball.vx << " " << ball.vy << " " << ball.radius << endl; + file << paddle.x << " " << paddle.y << " " << paddle.width << " " << paddle.height << " " << paddle.speed << endl; + + for (int i = 0; i < BRICK_ROWS; i++) + { + for (int j = 0; j < BRICK_COLS; j++) + { + file << bricks[i][j].x << " " << bricks[i][j].y << " " + << bricks[i][j].width << " " << bricks[i][j].height << " " + << bricks[i][j].visible << " "; + } + file << endl; + } + + if (gameMode == GAME_MODE_ADVANCED) + { + for (int i = 0; i < MAX_POWERUPS; i++) + { + file << powerups[i].x << " " << powerups[i].y << " " + << powerups[i].vy << " " << powerups[i].type << " " + << powerups[i].active << " " << powerups[i].collected << " "; + } + file << endl; + } + + file << score << endl; + file << lives << endl; + file << gameStarted << endl; + file << currentPlayerName << endl; + + file.close(); + } +} + +void loadGame() +{ + system("cls"); + ifstream file("saved_game.txt"); + if (!file.is_open()) + { + cout << BOLD << BRIGHT_RED << "\nNo unfinished game to load !" << endl; + cout << "Press any key to return" << RESET; + _getch(); + return; + } + + file >> gameMode; + file >> ball.x >> ball.y >> ball.vx >> ball.vy >> ball.radius; + file >> paddle.x >> paddle.y >> paddle.width >> paddle.height >> paddle.speed; + + if (paddle.width < MIN_PADDLE_WIDTH) + paddle.width = MIN_PADDLE_WIDTH; + if (paddle.width > MAX_PADDLE_WIDTH) + paddle.width = MAX_PADDLE_WIDTH; + + for (int i = 0; i < BRICK_ROWS; i++) + { + for (int j = 0; j < BRICK_COLS; j++) + { + file >> bricks[i][j].x >> bricks[i][j].y >> bricks[i][j].width >> bricks[i][j].height >> bricks[i][j].visible; + } + } + + if (gameMode == GAME_MODE_ADVANCED) + { + for (int i = 0; i < MAX_POWERUPS; i++) + { + file >> powerups[i].x >> powerups[i].y >> powerups[i].vy >> powerups[i].type >> powerups[i].active >> powerups[i].collected; + } + } + + file >> score; + file >> lives; + file >> gameStarted; + file.ignore(); + getline(file, currentPlayerName); + + file.close(); + + gameOver = false; + isPaused = false; + + cout << BOLD << BRIGHT_GREEN << "\nGame loaded successfully!" << endl; + cout << "Player: " << currentPlayerName << endl; + cout << "Score: " << score << endl; + cout << "Lives: " << lives << RESET << endl + << endl; + cout << BOLD << MAGENTA << "Continue the game ------> Press C" << RESET << endl; + cout << BOLD << BLUE << "Back to menu ------> Press M" << RESET; + + while (true) + { + if (_kbhit()) + { + char a = _getch(); + if (a == 'C' || a == 'c') + { + initScreenBuffer(); + hideCursor(); + runGame(); + } + else if (a == 'M' || a == 'm') + { + + menuMove(); + } + } + } +} + +void clearSavedGame() +{ + remove("saved_game.txt"); +} + +// ==================== تابع اصلی اجرای بازی ==================== +void runGame() +{ + while (!gameOver) + { + // اگر pause نیستیم، بازی رو render کن + if (!isPaused) + { + renderToBuffer(); + renderWithColorsOptimized(); + } + + if (!gameStarted && !isPaused) + { + while (true) + { + if (_kbhit()) + { + char key = _getch(); + if (key == ' ') + { + gameStarted = true; + break; + } + else if (key == 'p' || key == 'P') + { + isPaused = true; + pauseMove(); + break; + } + } + Sleep(100); + } + + if (gameOver) + break; + } + + // کنترل راکت - فقط وقتی pause نیستیم + if (!isPaused && _kbhit()) + { + char key = _getch(); + if (key == 'a' || key == 'A') + { + paddle.x -= paddle.speed; + if (paddle.x < 1) + paddle.x = 1; + + if (!gameStarted && !isPaused) + { + ball.x = paddle.x + paddle.width / 2.0f; + } + } + else if (key == 'd' || key == 'D') + { + paddle.x += paddle.speed; + if (paddle.x + paddle.width > BOARD_WIDTH - 1) + paddle.x = BOARD_WIDTH - 1 - paddle.width; + + if (!gameStarted && !isPaused) + { + ball.x = paddle.x + paddle.width / 2.0f; + } + } + else if (key == 'p' || key == 'P') + { + isPaused = true; + pauseMove(); + continue; + } + } + + if (gameStarted && !isPaused) + { + float deltaTime = 0.016f; // 60 فریم در ثانیه + updateBall(deltaTime); + + if (gameMode == GAME_MODE_ADVANCED) + { + activatePowerUps(deltaTime); + } + + // بررسی تمام شدن آجرها + bool allBricksDestroyed = true; + for (int i = 0; i < BRICK_ROWS; i++) + { + for (int j = 0; j < BRICK_COLS; j++) + { + if (bricks[i][j].visible) + { + allBricksDestroyed = false; + break; + } + } + if (!allBricksDestroyed) + break; + } + + checkPaddleCollision(); + checkBrickCollision(); + checkWallCollision(); + + if (allBricksDestroyed) + { + gameOver = true; + renderToBuffer(); + renderWithColorsOptimized(); + printVictory(); + saveGameHistory("Won"); + clearSavedGame(); + } + } + + Sleep(8); + } + + if (lives == 0) + { + clearMenuArea(); + saveGameHistory("Lost"); + printGameOver(); + clearSavedGame(); + } + + cout << "\nPress any key to return to main menu..." << endl; + _getch(); + + clearMenuArea(); + menuMove(); +} + +void newGame() +{ + system("cls"); + cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + << BOLD << BLUE << " ENTER YOUR NAME : " << RESET << endl; + cout << " "; + getline(cin, currentPlayerName); + while (currentPlayerName.empty()) + { + cout << BOLD << RED << " Enter your name please :)" << RESET; + Sleep(1000); + system("cls"); + cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + << BOLD << BLUE << " ENTER YOUR NAME : " << RESET << endl; + cout << " "; + getline(cin, currentPlayerName); + } + system("cls"); + selectGameMode(); + + initScreenBuffer(); + + initializeBricks(); + + if (gameMode == GAME_MODE_ADVANCED) + { + for (int i = 0; i < MAX_POWERUPS; i++) + { + powerups[i].active = false; + powerups[i].collected = false; + } + } + + system("cls"); + + paddle.x = INITIAL_PADDLE_X; + paddle.y = INITIAL_PADDLE_Y; + paddle.width = 10.0f; + paddle.height = 1.0f; + paddle.speed = PADDLE_SPEED; + + ball.x = INITIAL_BALL_X; + ball.y = INITIAL_BALL_Y; + ball.vx = BALL_SPEED; + ball.vy = -BALL_SPEED; + ball.radius = 0.5f; + + score = 0; + lives = 3; + gameOver = false; + gameStarted = false; + isPaused = false; + + resetBallAndPaddle(); + runGame(); +} + +// ==================== تابع main ==================== +int main() +{ + system("cls"); + hideCursor(); + // پیش‌ بارگذاری صداها برای کاهش تاخیر + preloadSounds(); + loadSettings(); + menuMove(); + + return 0; +} \ No newline at end of file