Advertisement
alien_fx_fiend

Y!Alchemy Pocket Pool (Final Integration !!!)

Sep 29th, 2024 (edited)
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 24.00 KB | None | 0 0
  1. #include <windows.h>
  2. #include <winsock2.h>
  3. #include <vector>
  4. #include <cmath>
  5. #include <cstdlib>
  6. #include <ctime>
  7. #include <string>
  8. #include <thread>
  9. #include <map>
  10.  
  11. #pragma comment(lib, "ws2_32.lib")
  12.  
  13. #define BALL_RADIUS 10
  14. #define TABLE_WIDTH 700
  15. #define TABLE_HEIGHT 400
  16. #define HOLE_RADIUS 15
  17. #define MAX_SHOT_POWER 20.0f
  18. #define GAME_MODE_STANDARD 1
  19. #define GAME_MODE_TIMED 2
  20.  
  21. // Struct to represent a ball
  22. struct Ball {
  23.     float x, y, vx, vy, spinX, spinY;
  24.     COLORREF color;
  25.     bool isPocketed;
  26.     bool isStripe;
  27.     int radius = BALL_RADIUS;
  28.     float mass = 1.0f;
  29. };
  30.  
  31. // Player struct
  32. struct Player {
  33.     bool isSolid;
  34.     std::vector<Ball> pocketedBalls;
  35.     bool turn;
  36.     bool fouled;
  37.     bool isAI;
  38.     int score;
  39.     int fouls;
  40. };
  41.  
  42. // Lobby for multiplayer games
  43. std::map<int, SOCKET> lobby;
  44. std::vector<std::string> availableGames;
  45. int playerID;
  46. bool inLobby = true;
  47.  
  48. // Multiplayer network setup (TCP for lobbies)
  49. SOCKET sock;
  50. SOCKADDR_IN serverAddr, clientAddr;
  51. char recvBuffer[512];
  52. bool isMultiplayer = false;
  53. bool isHost = false;
  54.  
  55. // Global Variables
  56. Ball cueBall = {100, 250, 0, 0, 0, 0, RGB(255, 255, 255), false, false}; // White cue ball
  57. Ball blackBall = {400, 250, 0, 0, 0, 0, RGB(0, 0, 0), false, false}; // Black 8-ball
  58. Player player1 = {true, {}, true, false, false, 0, 0}; // Human player
  59. Player player2 = {false, {}, false, false, true, 0, 0}; // AI/remote player
  60. std::vector<Ball> balls;
  61. HWND hwnd;
  62. bool gameOver = false;
  63. Player* currentPlayer = &player1;
  64. std::string playerName;
  65. std::vector<Ball> replayFrames;  // Store frames for replay
  66.  
  67. // Cue variables for control
  68. float cueAngle = 0.0f; // Angle of the shot in radians
  69. float shotPower = 0.0f; // Power of the shot
  70. float cueSpinX = 0.0f; // Horizontal spin (English)
  71. float cueSpinY = 0.0f; // Vertical spin (English)
  72. POINT mousePos; // Mouse position for aiming and power control
  73.  
  74. // Customization options
  75. COLORREF tableColor = RGB(34, 139, 34);  // Default green table
  76. COLORREF cueColor = RGB(139, 69, 19);  // Default brown cue
  77. COLORREF stripeBallColor = RGB(255, 255, 0);  // Default yellow stripe
  78. COLORREF solidBallColor = RGB(255, 0, 0);  // Default red solid
  79.  
  80. // UI Elements
  81. RECT powerMeterRect = {750, 50, 780, 450}; // Power meter on the right side
  82. RECT spinIndicatorRect = {60, 480, 140, 560}; // Spin indicator near the bottom
  83. int powerMeterLevel = 0; // Indicates shot power level
  84. int gameMode = GAME_MODE_STANDARD;  // Default game mode
  85. int timer = 120;  // 2-minute timer for timed mode
  86. bool replayMode = false;  // Track if replay mode is active
  87.  
  88. // Utility functions
  89. bool IsColliding(Ball& b1, Ball& b2);
  90. void ResolveCollision(Ball& b1, Ball& b2);
  91. bool IsPocketed(Ball& ball);
  92. void HandleFouls(Player& player);
  93. void ApplySpin(Ball& ball);
  94. void AdjustShotPower(POINT& mousePos);
  95. void DrawPowerMeter(HDC hdc);
  96. void DrawSpinIndicator(HDC hdc);
  97. void SwitchTurns();
  98. void AITakeShot();  // AI player logic
  99. void PredictShot(Ball& ball, float& shotScore); // AI shot prediction logic
  100. void CheckGameOver();
  101. void UpdateScores(HDC hdc);
  102. void StartTimedMode();
  103. void InitNetworkLobby();  // Initialize lobby-based multiplayer system
  104. void InitNetwork(bool isHost);  // Initialize internet multiplayer network
  105. void SendNetworkData(const std::string& data); // Send data over the network
  106. void ReceiveNetworkData();  // Receive data from the network
  107. void DisplayLobbyMenu();  // Lobby system UI
  108. void CustomizationMenu();  // Customization UI
  109. void SelectCustomization();  // Apply customization options
  110. void ReplayShot();  // Replay mode logic
  111. void CheckFoul(Player& player, Ball& cueBall, std::vector<Ball>& balls) // Remove if Redundant !!!
  112. void DisplayFoul(); // Remove if Redundant !!!
  113. void HandlePlayerTurn(Player& player, Ball& cueBall); // Remove if Redundant !!!
  114.  
  115. // Function to draw the table and pockets with customization
  116. void DrawTable(HDC hdc) {
  117.     // Set table color
  118.     HBRUSH tableBrush = CreateSolidBrush(tableColor);  // Apply table customization
  119.     RECT tableRect = {50, 50, 750, 450}; // Set size of the table
  120.     FillRect(hdc, &tableRect, tableBrush);
  121.  
  122.     // Draw pocket holes (black)
  123.     HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0)); // Black pockets
  124.     SelectObject(hdc, blackBrush);
  125.     Ellipse(hdc, 55, 55, 55 + HOLE_RADIUS * 2, 55 + HOLE_RADIUS * 2); // Top-left
  126.     Ellipse(hdc, 745 - HOLE_RADIUS * 2, 55, 745, 55 + HOLE_RADIUS * 2); // Top-right
  127.     Ellipse(hdc, 55, 445 - HOLE_RADIUS * 2, 55 + HOLE_RADIUS * 2, 445); // Bottom-left
  128.     Ellipse(hdc, 745 - HOLE_RADIUS * 2, 445 - HOLE_RADIUS * 2, 745, 445); // Bottom-right
  129.     Ellipse(hdc, 395 - HOLE_RADIUS * 2, 55, 405 + HOLE_RADIUS * 2, 55 + HOLE_RADIUS * 2); // Top-middle
  130.     Ellipse(hdc, 395 - HOLE_RADIUS * 2, 445 - HOLE_RADIUS * 2, 405 + HOLE_RADIUS * 2, 445); // Bottom-middle
  131. }
  132.  
  133. // Function to draw a ball (solid or stripe) with customization
  134. void DrawBall(HDC hdc, Ball& ball) {
  135.     HBRUSH ballBrush = CreateSolidBrush(ball.isStripe ? stripeBallColor : solidBallColor);  // Custom ball colors
  136.     HPEN ballPen = CreatePen(PS_SOLID, 2, RGB(0, 0, 0)); // Black border
  137.     SelectObject(hdc, ballBrush);
  138.     SelectObject(hdc, ballPen);
  139.  
  140.     // Draw the ball (if not pocketed)
  141.     if (!ball.isPocketed) {
  142.         // Draw shadow first for 3D effect
  143.         Ellipse(hdc, ball.x - ball.radius, ball.y - ball.radius, ball.x + ball.radius, ball.y + ball.radius);
  144.         // Draw stripe if it's a striped ball
  145.         if (ball.isStripe) {
  146.             HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
  147.             SelectObject(hdc, whiteBrush);
  148.             Rectangle(hdc, ball.x - ball.radius, ball.y - 3, ball.x + ball.radius, ball.y + 3);
  149.         }
  150.     }
  151.  
  152. /*     if (!ball.isPocketed) {
  153.         // Draw shadow first for 3D effect
  154.         Ellipse(hdc, ball.x - ball.radius + 3, ball.y - ball.radius + 3, ball.x + ball.radius + 3, ball.y + ball.radius + 3);
  155.  
  156.         // Draw the ball with shading
  157.         SelectObject(hdc, shadowBrush);
  158.         Ellipse(hdc, ball.x - ball.radius, ball.y - ball.radius, ball.x + ball.radius, ball.y + ball.radius);
  159.     } */
  160.  
  161.     // Cleanup
  162.     DeleteObject(ballBrush);
  163.     DeleteObject(ballPen);
  164. }
  165.  
  166. // Function to handle ball physics with spin and friction
  167. void HandleBallPhysics(Ball& ball, std::vector<Ball>& allBalls) {
  168.     // Update position based on velocity
  169.     ball.x += ball.vx + ball.spinX;
  170.     ball.y += ball.vy + ball.spinY;
  171.  
  172.     // Handle table boundary collision (bounce off walls)
  173.     if (ball.x <= 50 || ball.x >= 750) ball.vx *= -1; // Horizontal
  174.     if (ball.y <= 50 || ball.y >= 450) ball.vy *= -1; // Vertical
  175.  
  176.     // Handle ball-to-ball collisions
  177.     for (Ball& otherBall : allBalls) {
  178.         if (&ball != &otherBall && IsColliding(ball, otherBall)) {
  179.             ResolveCollision(ball, otherBall);
  180.         }
  181.     }
  182.  
  183.     // Apply friction and reduce spin over time
  184.     ball.vx *= 0.98;
  185.     ball.vy *= 0.98;
  186.     ball.spinX *= 0.97;
  187.     ball.spinY *= 0.97;
  188. }
  189.  
  190. // Apply spin to a ball (English)
  191. void ApplySpin(Ball& ball) {
  192.     ball.spinX += cueSpinX * 0.1f; // Horizontal spin effect
  193.     ball.spinY += cueSpinY * 0.1f; // Vertical spin effect
  194. }
  195.  
  196. // Check if two balls are colliding
  197. bool IsColliding(Ball& b1, Ball& b2) {
  198.     float dx = b1.x - b2.x;
  199.     float dy = b1.y - b2.y;
  200.     float distance = sqrt(dx * dx + dy * dy);
  201.     return distance < (b1.radius + b2.radius);
  202. }
  203.  
  204. // Resolve collision between two balls
  205. void ResolveCollision(Ball& b1, Ball& b2) {
  206.     float nx = b2.x - b1.x;
  207.     float ny = b2.y - b1.y;
  208.     float distance = sqrt(nx * nx + ny * ny);
  209.     nx /= distance;
  210.     ny /= distance;
  211.  
  212.     float kx = (b1.vx - b2.vx) * nx;
  213.     float ky = (b1.vy - b2.vy) * ny;
  214.     float p = 2.0 * (kx * nx + ky * ny) / (b1.mass + b2.mass);
  215.  
  216.     b1.vx -= p * b2.mass * nx;
  217.     b1.vy -= p * b2.mass * ny;
  218.     b2.vx += p * b1.mass * nx;
  219.     b2.vy += p * b1.mass * ny;
  220. }
  221.  
  222. // Adjust shot power based on mouse position
  223. void AdjustShotPower(POINT& mousePos) {
  224.     float distX = mousePos.x - cueBall.x;
  225.     float distY = mousePos.y - cueBall.y;
  226.     shotPower = sqrt(distX * distX + distY * distY) / 10.0f; // Adjust this value for power sensitivity
  227.     shotPower = min(shotPower, MAX_SHOT_POWER); // Cap the shot power
  228.     powerMeterLevel = (int)(shotPower / MAX_SHOT_POWER * 100); // Set power level for power meter
  229. }
  230.  
  231. // AI shot prediction logic (multi-step and tactical)
  232. void PredictShot(Ball& ball, float& shotScore) {
  233.     // Simulate shot, predict outcome, and score based on potential outcome
  234.     float distX = ball.x - cueBall.x;
  235.     float distY = ball.y - cueBall.y;
  236.     float dist = sqrt(distX * distX + distY * distY);
  237.     float angle = atan2(distY, distX);
  238.  
  239.     // Calculate shot score based on distance and angle
  240.     shotScore = -dist + cos(angle) * 50.0f;
  241.  
  242.     // Increase score for defensive plays or multi-step shot setups
  243.     if (distX < 100 && distY < 100) {
  244.         shotScore += 50.0f;  // Bonus for defensive or setup shots
  245.     }
  246. }
  247.  
  248. // Function to check for pocketing a ball
  249. bool IsPocketed(Ball& ball) {
  250.     return (ball.x < 55 + HOLE_RADIUS && ball.y < 55 + HOLE_RADIUS) || // Top-left pocket
  251.            (ball.x > 745 - HOLE_RADIUS && ball.y < 55 + HOLE_RADIUS) || // Top-right pocket
  252.            (ball.x < 55 + HOLE_RADIUS && ball.y > 445 - HOLE_RADIUS) || // Bottom-left pocket
  253.            (ball.x > 745 - HOLE_RADIUS && ball.y > 445 - HOLE_RADIUS) || // Bottom-right pocket
  254.            (ball.x > 395 - HOLE_RADIUS && ball.x < 405 + HOLE_RADIUS &&
  255.             (ball.y < 55 + HOLE_RADIUS || ball.y > 445 - HOLE_RADIUS)); // Middle pockets
  256. }
  257.  
  258. // Function to draw the power meter
  259. void DrawPowerMeter(HDC hdc) {
  260.     HBRUSH powerBrush = CreateSolidBrush(RGB(0, 255, 0)); // Green for power
  261.     RECT powerLevel = powerMeterRect;
  262.     powerLevel.top = powerMeterRect.bottom - powerMeterLevel * (powerMeterRect.bottom - powerMeterRect.top) / 100; // Adjust height
  263.  
  264.     FillRect(hdc, &powerLevel, powerBrush);
  265.     DeleteObject(powerBrush);
  266. }
  267.  
  268. // Function to draw the spin indicator
  269. void DrawSpinIndicator(HDC hdc) {
  270.     HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255)); // Cue ball color
  271.     Ellipse(hdc, spinIndicatorRect.left, spinIndicatorRect.top, spinIndicatorRect.right, spinIndicatorRect.bottom); // Draw cue ball
  272.  
  273.     // Draw spin dot (shows where spin is being applied)
  274.     HBRUSH redBrush = CreateSolidBrush(RGB(255, 0, 0)); // Red dot for spin
  275.     int spinX = (int)(cueSpinX * 10); // Scale spin for visualization
  276.     int spinY = (int)(cueSpinY * 10);
  277.     int centerX = (spinIndicatorRect.left + spinIndicatorRect.right) / 2;
  278.     int centerY = (spinIndicatorRect.top + spinIndicatorRect.bottom) / 2;
  279.  
  280.     Ellipse(hdc, centerX + spinX - 5, centerY + spinY - 5, centerX + spinX + 5, centerY + spinY + 5); // Spin dot
  281.     DeleteObject(whiteBrush);
  282.     DeleteObject(redBrush);
  283. }
  284.  
  285. // Handle fouls (e.g., pocketing the cue ball or failing to hit a ball)
  286. void HandleFouls(Player& player) {
  287.     if (IsPocketed(cueBall)) {
  288.         player.fouled = true;
  289.         player.fouls++;
  290.     }
  291. }
  292.  
  293. // Multiplayer setup (TCP/IP for internet)
  294. void InitNetwork(bool isHost) {
  295.     WSADATA wsa;
  296.     WSAStartup(MAKEWORD(2, 2), &wsa);
  297.     sock = socket(AF_INET, SOCK_STREAM, 0);  // Use TCP for internet play
  298.  
  299.     memset(&serverAddr, 0, sizeof(serverAddr));
  300.     serverAddr.sin_family = AF_INET;
  301.     serverAddr.sin_port = htons(8888);
  302.  
  303.     if (isHost) {
  304.         serverAddr.sin_addr.s_addr = INADDR_ANY;
  305.         bind(sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
  306.         listen(sock, 1);
  307.         int clientSize = sizeof(clientAddr);
  308.         sock = accept(sock, (SOCKADDR*)&clientAddr, &clientSize);
  309.         isMultiplayer = true;
  310.         isHost = true;
  311.     } else {
  312.         serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");  // Connect to host IP
  313.         connect(sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
  314.         isMultiplayer = true;
  315.     }
  316. }
  317.  
  318. // Send data over the network
  319. void SendNetworkData(const std::string& data) {
  320.     send(sock, data.c_str(), data.size(), 0);
  321. }
  322.  
  323. // Receive data from the network
  324. void ReceiveNetworkData() {
  325.     int bytesReceived = recv(sock, recvBuffer, sizeof(recvBuffer), 0);
  326.     recvBuffer[bytesReceived] = '\0';
  327.    
  328.     // Parse and process opponent's move
  329.     std::string receivedData(recvBuffer);
  330.     // Process opponent's shot...
  331. }
  332.  
  333. // Check if the black ball has been pocketed and declare the winner
  334. void CheckGameOver() {
  335.     if (IsPocketed(blackBall)) {
  336.         gameOver = true;
  337.         Player* winner = (currentPlayer == &player1) ? &player2 : &player1;
  338.         std::string result = winner == &player1 ? "Player 1 Wins!" : "Player 2 Wins!";
  339.         SendNetworkData(result);
  340.         MessageBox(hwnd, result.c_str(), "Game Over", MB_OK);
  341.         PostQuitMessage(0);
  342.     }
  343. }
  344.  
  345. // Update scores based on pocketed balls
  346. void UpdateScores(HDC hdc) {
  347.     wchar_t scoreText[100];
  348.     wsprintf(scoreText, L"Player 1 Score: %d | Player 2 Score: %d", player1.score, player2.score);
  349.     SetTextColor(hdc, RGB(0, 0, 0));
  350.     SetBkMode(hdc, TRANSPARENT);
  351.     TextOut(hdc, 300, 470, scoreText, lstrlen(scoreText));
  352.  
  353.     // Display fouls
  354.     wchar_t foulText[100];
  355.     wsprintf(foulText, L"Fouls: Player 1: %d | Player 2: %d", player1.fouls, player2.fouls);
  356.     TextOut(hdc, 300, 490, foulText, lstrlen(foulText));
  357. }
  358.  
  359. // Replay mode: record frames
  360. void RecordReplayFrame() {
  361.     std::vector<Ball> frame;
  362.     for (const auto& ball : balls) {
  363.         frame.push_back(ball);
  364.     }
  365.     replayFrames.push_back(frame);
  366. }
  367.  
  368. // Replay mode: show replay frames
  369. void ShowReplayFrames(HDC hdc) {
  370.     if (!replayMode) return;
  371.  
  372.     for (size_t i = 0; i < replayFrames.size(); ++i) {
  373.         for (Ball& ball : replayFrames[i]) {
  374.             DrawBall(hdc, ball);
  375.         }
  376.         Sleep(50);  // Slow down replay for visualization
  377.     }
  378.  
  379.     replayMode = false;  // Exit replay mode after showing
  380. }
  381.  
  382. // Apply customization options from menu
  383. void SelectCustomization() {
  384.     tableColor = RGB(0, 100, 100);  // Example: Teal table
  385.     cueColor = RGB(200, 200, 50);   // Example: Golden cue
  386.     stripeBallColor = RGB(0, 0, 255);   // Example: Blue stripe
  387.     solidBallColor = RGB(0, 255, 0);    // Example: Green solid
  388. }
  389.  
  390. // Function to display the lobby menu
  391. void DisplayLobbyMenu() {
  392.     std::cout << "Enter your player name: ";
  393.     std::cin >> playerName;
  394.  
  395.     std::cout << "\nAvailable Games:\n";
  396.     for (const auto& game : availableGames) {
  397.         std::cout << "- " << game << std::endl;
  398.     }
  399.  
  400.     std::cout << "Press 'H' to Host a new game or 'J' to join one: ";
  401.     char choice;
  402.     std::cin >> choice;
  403.  
  404.     if (choice == 'H') {
  405.         InitNetwork(true);  // Host a new game
  406.     } else if (choice == 'J') {
  407.         InitNetwork(false);  // Join an existing game
  408.     }
  409. }
  410.  
  411. // Lobby-based network initialization (TCP for hosting/joining games)
  412. void InitNetworkLobby() {
  413.     WSADATA wsa;
  414.     WSAStartup(MAKEWORD(2, 2), &wsa);
  415.     sock = socket(AF_INET, SOCK_STREAM, 0);
  416.  
  417.     memset(&serverAddr, 0, sizeof(serverAddr));
  418.     serverAddr.sin_family = AF_INET;
  419.     serverAddr.sin_port = htons(8888);
  420.     serverAddr.sin_addr.s_addr = INADDR_ANY;
  421.  
  422.     if (bind(sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
  423.         MessageBox(hwnd, "Failed to create lobby", "Error", MB_OK);
  424.         return;
  425.     }
  426.  
  427.     listen(sock, 10);  // Allow up to 10 players to join
  428.  
  429.     while (inLobby) {
  430.         int clientSize = sizeof(clientAddr);
  431.         SOCKET clientSock = accept(sock, (SOCKADDR*)&clientAddr, &clientSize);
  432.         if (clientSock != INVALID_SOCKET) {
  433.             playerID++;
  434.             lobby[playerID] = clientSock;
  435.             std::thread([](SOCKET s, int id) {
  436.                 char buffer[512];
  437.                 int received = recv(s, buffer, sizeof(buffer), 0);
  438.                 buffer[received] = '\0';
  439.  
  440.                 lobby[id] = s;
  441.  
  442.             }, clientSock, playerID).detach();
  443.         }
  444.     }
  445. }
  446.  
  447. // Function to start the timed mode game
  448. void StartTimedMode() {
  449.     gameMode = GAME_MODE_TIMED;
  450.     timer = 120; // 2-minute timer
  451.  
  452.  
  453.     SetTimer(hwnd, 1, 1000, NULL);  // Start a 1-second timer
  454. }
  455.  
  456. // Timer event handler
  457. void HandleTimerEvent() {
  458.     if (gameMode == GAME_MODE_TIMED) {
  459.         if (timer > 0) {
  460.             timer--;
  461.         } else {
  462.             // Time up, game over
  463.             MessageBox(hwnd, "Time's up! Game Over!", "Game Over", MB_OK);
  464.             gameOver = true;
  465.             PostQuitMessage(0);
  466.         }
  467.     }
  468. }
  469.  
  470. // Function to draw the cue stick and aiming aids
  471. void DrawCueStick(HDC hdc, Ball& cueBall, float angle, float power) {
  472.     // Cue stick
  473.     HPEN cuePen = CreatePen(PS_SOLID, 6, RGB(139, 69, 19)); // Brown cue stick
  474.     SelectObject(hdc, cuePen);
  475.  
  476.     // Draw the cue stick based on angle
  477.     MoveToEx(hdc, cueBall.x, cueBall.y, NULL);
  478.     LineTo(hdc, cueBall.x + power * cos(angle), cueBall.y + power * sin(angle)); // Stick
  479.  
  480.     // Aiming aid (dash line to ball trajectory)
  481.     HPEN dashPen = CreatePen(PS_DASH, 1, RGB(0, 0, 255)); // Blue aiming aid
  482.     SelectObject(hdc, dashPen);
  483.     LineTo(hdc, cueBall.x + 150 * cos(angle), cueBall.y + 150 * sin(angle)); // Aiming aid
  484.  
  485.     DeleteObject(cuePen);
  486.     DeleteObject(dashPen);
  487. }
  488.  
  489. // AI takes a shot with advanced prediction logic
  490. void AITakeShot() {
  491.     Ball* targetBall = nullptr;
  492.     float bestScore = -9999.0f;
  493.  
  494.     for (Ball& ball : balls) {
  495.         if (!ball.isPocketed && currentPlayer->isSolid == !ball.isStripe) {
  496.             float shotScore;
  497.             PredictShot(ball, shotScore);
  498.  
  499.             if (shotScore > bestScore) {
  500.                 bestScore = shotScore;
  501.                 targetBall = &ball;
  502.             }
  503.         }
  504.     }
  505.  
  506.     if (targetBall) {
  507.         cueAngle = atan2(targetBall->y - cueBall.y, targetBall->x - cueBall.x);
  508.         shotPower = (rand() % 10 + 10) / 10.0f;
  509.  
  510.         cueBall.vx = shotPower * cos(cueAngle);
  511.         cueBall.vy = shotPower * sin(cueAngle);
  512.  
  513.         ApplySpin(cueBall);
  514.         SwitchTurns();
  515.     }
  516. }
  517.  
  518. // Switch turns between players after each shot or foul
  519. void SwitchTurns() {
  520.     currentPlayer->turn = false;
  521.     currentPlayer = (currentPlayer == &player1) ? &player2 : &player1;
  522.     currentPlayer->turn = true;
  523.  
  524.     // Trigger AI or network action if it's AI's or remote player's turn
  525.     if (currentPlayer->isAI) {
  526.         AITakeShot();
  527.     } else if (isMultiplayer) {
  528.         ReceiveNetworkData();  // Get the opponent's move
  529.     }
  530. }
  531.  
  532. // Remove if Redundant !!!
  533. /* void HandleFouls(Player& player) {
  534.     if (IsPocketed(cueBall)) {
  535.         player.fouled = true;
  536.     }
  537. } */
  538.  
  539. // Remove if Redundant !!!
  540. // Game logic (foul detection, player switching, pocket checking)
  541. void CheckFoul(Player& player, Ball& cueBall, std::vector<Ball>& balls) {
  542.     if (player.isSolid && IsPocketed(blackBall)) {
  543.         // 8-ball pocketed before all solids, foul
  544.         DisplayFoul();
  545.         player.canMoveCue = true;
  546.     } else if (!player.isSolid && IsPocketed(blackBall)) {
  547.         // 8-ball pocketed before all stripes, foul
  548.         DisplayFoul();
  549.         player.canMoveCue = true;
  550.     }
  551. }
  552.  
  553. // Remove if Redundant !!!
  554. // Display foul text
  555. void DisplayFoul() {
  556.     HDC hdc = GetDC(hwnd);
  557.     SetTextColor(hdc, RGB(255, 0, 0));
  558.     TextOut(hdc, 10, 10, "FOUL!", 5);
  559.     ReleaseDC(hwnd, hdc);
  560. }
  561.  
  562. // Remove if Redundant !!!
  563. // Function to handle player actions (spin, re-spotting, fouls)
  564. void HandlePlayerTurn(Player& player, Ball& cueBall) {
  565.     if (player.fouled) {
  566.         // Cue ball re-spotting
  567.         cueBall.x = 100;
  568.         cueBall.y = 250;
  569.         cueBall.vx = cueBall.vy = cueBall.spinX = cueBall.spinY = 0;
  570.         player.fouled = false;
  571.     }
  572. }
  573.  
  574. // Main game loop
  575. void GameLoop(HDC hdc) {
  576.     // Clear screen
  577.     RECT clientRect;
  578.     GetClientRect(hwnd, &clientRect);
  579.     FillRect(hdc, &clientRect, (HBRUSH)(COLOR_WINDOW + 1));
  580.  
  581.     // Draw table and balls
  582.     DrawTable(hdc);
  583.  
  584.     for (Ball& ball : balls) {
  585.         HandleBallPhysics(ball, balls);
  586.         DrawBall(hdc, ball);
  587.         if (IsPocketed(ball)) ball.isPocketed = true; // Pocket the ball
  588.     }
  589.  
  590.     // Draw the cue ball
  591.     DrawBall(hdc, cueBall);
  592.  
  593.     if (!gameOver) {
  594.         HandleFouls(*currentPlayer);
  595.         CheckGameOver();
  596.         if (gameMode == GAME_MODE_TIMED) {
  597.             wchar_t timerText[50];
  598.             wsprintf(timerText, L"Time Remaining: %d seconds", timer);
  599.             TextOut(hdc, 350, 20, timerText, lstrlen(timerText));
  600.         }
  601.     }
  602.  
  603.     DrawCueStick(hdc, cueBall, cueAngle, shotPower);
  604.     DrawPowerMeter(hdc);
  605.     DrawSpinIndicator(hdc);
  606.     UpdateScores(hdc);
  607. }
  608.  
  609. // Main game window procedure
  610. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  611.     PAINTSTRUCT ps;
  612.     HDC hdc;
  613.  
  614.     switch (msg) {
  615.         case WM_PAINT:
  616.             hdc = BeginPaint(hwnd, &ps);
  617.             GameLoop(hdc);
  618.             EndPaint(hwnd, &ps);
  619.             break;
  620.         case WM_MOUSEMOVE:
  621.             mousePos.x = LOWORD(lParam);
  622.             mousePos.y = HIWORD(lParam);
  623.             AdjustShotPower(mousePos);
  624.             cueAngle = atan2(mousePos.y - cueBall.y, mousePos.x - cueBall.x);
  625.             InvalidateRect(hwnd, NULL, FALSE);
  626.             break;
  627.         case WM_LBUTTONDOWN:
  628.             cueBall.vx = shotPower * cos(cueAngle);
  629.             cueBall.vy = shotPower * sin(cueAngle);
  630.             ApplySpin(cueBall);
  631.             if (isMultiplayer) {
  632.                 std::string data = "SHOT:" + std::to_string(cueBall.vx) + "," + std::to_string(cueBall.vy);
  633.                 SendNetworkData(data);
  634.             }
  635.             SwitchTurns();
  636.             InvalidateRect(hwnd, NULL, FALSE);
  637.             break;
  638.         case WM_KEYDOWN:
  639.             switch (wParam) {
  640.                 case VK_LEFT:
  641.                     cueSpinX -= 0.1f;
  642.                     break;
  643.                 case VK_RIGHT:
  644.                     cueSpinX += 0.1f;
  645.                     break;
  646.                 case VK_UP:
  647.                     cueSpinY -= 0.1f;
  648.                     break;
  649.                 case VK_DOWN:
  650.                     cueSpinY += 0.1f;
  651.                     break;
  652.                 case 'T':
  653.                     StartTimedMode();
  654.                     break;
  655.                 case 'M':
  656.                     InitNetwork(true);
  657.                     break;
  658.                 case 'C':
  659.                     InitNetwork(false);
  660.                     break;
  661.                 case 'R':
  662.                     replayMode = true;
  663.                     InvalidateRect(hwnd, NULL, FALSE);
  664.                     break;
  665.                 case 'P':
  666.                     CustomizationMenu();
  667.                     InvalidateRect(hwnd, NULL, FALSE);
  668.                     break;
  669.             }
  670.             InvalidateRect(hwnd, NULL, FALSE);
  671.             break;
  672.         case WM_DESTROY:
  673.             closesocket(sock);
  674.             WSACleanup();
  675.             PostQuitMessage(0);
  676.             break;
  677.         default:
  678.             return DefWindowProc(hwnd, msg, wParam, lParam);
  679.     }
  680.     return 0;
  681. }
  682.  
  683. // WinMain
  684. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
  685.     MSG msg;
  686.     WNDCLASS wc = {0};
  687.     wc.lpfnWndProc = WndProc;
  688.     wc.hInstance = hInstance;
  689.     wc.lpszClassName = "BilliardsGame";
  690.  
  691.     RegisterClass(&wc);
  692.  
  693.     hwnd = CreateWindowEx(0, "BilliardsGame", "Enhanced 8-Ball Billiards", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);
  694.     ShowWindow(hwnd, nCmdShow);
  695.  
  696.     // Initialize balls (8-ball game setup)
  697.     balls.push_back(cueBall);
  698.     balls.push_back(blackBall);
  699.  
  700.     // Add all solid and stripe balls
  701.     for (int i = 1; i <= 7; ++i) {
  702.         Ball solidBall = {150 + i * 30, 200, 0, 0, 0, 0, solidBallColor, false, false};
  703.         balls.push_back(solidBall);
  704.  
  705.         Ball stripeBall = {150 + i * 30, 300, 0, 0, 0, 0, stripeBallColor, false, true};
  706.         balls.push_back(stripeBall);
  707.     }
  708.  
  709.     // Seed the random number generator for AI shots
  710.     srand((unsigned)time(NULL));
  711.  
  712.     while (GetMessage(&msg, NULL, 0, 0)) {
  713.         TranslateMessage(&msg);
  714.         DispatchMessage(&msg);
  715.     }
  716.  
  717.     return msg.wParam;
  718. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement