fork download
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include <string.h>
  5. #include <time.h>
  6.  
  7. #ifdef _WIN32
  8. #include <windows.h>
  9. #include <GL/gl.h>
  10. #include <GL/glu.h>
  11. #include <GL/glut.h>
  12. #include <wininet.h>
  13. #pragma comment(lib, "wininet.lib")
  14. #else
  15. #include <OpenGL/gl.h>
  16. #include <OpenGL/glu.h>
  17. #include <GLUT/glut.h>
  18. #include <curl/curl.h>
  19. #endif
  20.  
  21. // Game constants
  22. #define WORLD_SIZE 50.0f
  23. #define PLAYER_SPEED 0.2f
  24. #define ENEMY_COUNT 5
  25. #define MAX_PROJECTILES 20
  26. #define PROJECTILE_SPEED 0.5f
  27. #define MAX_USERNAME 50
  28. #define MAX_EMAIL 100
  29.  
  30. // Game states
  31. typedef enum {
  32. GAME_STATE_LOGIN,
  33. GAME_STATE_PLAYING,
  34. GAME_STATE_MENU
  35. } GameState;
  36.  
  37. // User authentication structure
  38. typedef struct {
  39. char username[MAX_USERNAME];
  40. char email[MAX_EMAIL];
  41. char provider[20]; // "facebook", "gmail", or "guest"
  42. int user_id;
  43. int is_logged_in;
  44. int high_score;
  45. int total_games;
  46. } User;
  47.  
  48. // Login button structure
  49. typedef struct {
  50. float x, y, width, height;
  51. char text[50];
  52. float r, g, b;
  53. int provider_type; // 0=facebook, 1=gmail, 2=guest
  54. } LoginButton;
  55.  
  56. // Player structure
  57. typedef struct {
  58. float x, y, z;
  59. float rotation;
  60. int health;
  61. int score;
  62. float weapon_cooldown;
  63. } Player;
  64.  
  65. // Enemy structure
  66. typedef struct {
  67. float x, y, z;
  68. float rotation;
  69. int health;
  70. int active;
  71. float ai_timer;
  72. } Enemy;
  73.  
  74. // Projectile structure
  75. typedef struct {
  76. float x, y, z;
  77. float dx, dy, dz;
  78. int active;
  79. int from_player;
  80. } Projectile;
  81.  
  82. // Global game state
  83. Player player = {0.0f, 1.0f, 0.0f, 0.0f, 100, 0, 0.0f};
  84. Enemy enemies[ENEMY_COUNT];
  85. Projectile projectiles[MAX_PROJECTILES];
  86. User current_user = {"", "", "", 0, 0, 0, 0};
  87. GameState game_state = GAME_STATE_LOGIN;
  88. LoginButton login_buttons[3];
  89. float camera_angle_x = 30.0f;
  90. float camera_angle_y = 0.0f;
  91. float camera_distance = 15.0f;
  92. int keys[256] = {0};
  93. int mouse_x, mouse_y;
  94. float time_counter = 0.0f;
  95. int window_width = 800, window_height = 600;
  96.  
  97. // HTTP response structure for API calls
  98. typedef struct {
  99. char *data;
  100. size_t size;
  101. } HTTPResponse;
  102.  
  103. // Write callback for HTTP requests
  104. size_t write_callback(void *contents, size_t size, size_t nmemb, HTTPResponse *response) {
  105. size_t real_size = size * nmemb;
  106. char *ptr = realloc(response->data, response->size + real_size + 1);
  107. if (ptr == NULL) {
  108. printf("Not enough memory (realloc returned NULL)\n");
  109. return 0;
  110. }
  111. response->data = ptr;
  112. memcpy(&(response->data[response->size]), contents, real_size);
  113. response->size += real_size;
  114. response->data[response->size] = 0;
  115. return real_size;
  116. }
  117.  
  118. // Initialize login system
  119. void init_login_system() {
  120. // Facebook login button
  121. login_buttons[0].x = 250;
  122. login_buttons[0].y = 200;
  123. login_buttons[0].width = 300;
  124. login_buttons[0].height = 50;
  125. strcpy(login_buttons[0].text, "Login with Facebook");
  126. login_buttons[0].r = 0.23f; login_buttons[0].g = 0.35f; login_buttons[0].b = 0.60f;
  127. login_buttons[0].provider_type = 0;
  128.  
  129. // Gmail login button
  130. login_buttons[1].x = 250;
  131. login_buttons[1].y = 280;
  132. login_buttons[1].width = 300;
  133. login_buttons[1].height = 50;
  134. strcpy(login_buttons[1].text, "Login with Gmail");
  135. login_buttons[1].r = 0.85f; login_buttons[1].g = 0.26f; login_buttons[1].b = 0.21f;
  136. login_buttons[1].provider_type = 1;
  137.  
  138. // Guest login button
  139. login_buttons[2].x = 250;
  140. login_buttons[2].y = 360;
  141. login_buttons[2].width = 300;
  142. login_buttons[2].height = 50;
  143. strcpy(login_buttons[2].text, "Play as Guest");
  144. login_buttons[2].r = 0.5f; login_buttons[2].g = 0.5f; login_buttons[2].b = 0.5f;
  145. login_buttons[2].provider_type = 2;
  146. }
  147.  
  148. // Simulate OAuth authentication (in real implementation, this would open browser)
  149. int authenticate_with_provider(int provider_type) {
  150. switch(provider_type) {
  151. case 0: // Facebook
  152. printf("Opening Facebook OAuth... (simulated)\n");
  153. strcpy(current_user.username, "Facebook User");
  154. strcpy(current_user.email, "user@facebook.com");
  155. strcpy(current_user.provider, "facebook");
  156. current_user.user_id = 12345;
  157. break;
  158. case 1: // Gmail
  159. printf("Opening Google OAuth... (simulated)\n");
  160. strcpy(current_user.username, "Gmail User");
  161. strcpy(current_user.email, "user@gmail.com");
  162. strcpy(current_user.provider, "gmail");
  163. current_user.user_id = 67890;
  164. break;
  165. case 2: // Guest
  166. printf("Playing as guest...\n");
  167. strcpy(current_user.username, "Guest");
  168. strcpy(current_user.email, "");
  169. strcpy(current_user.provider, "guest");
  170. current_user.user_id = rand() % 10000;
  171. break;
  172. }
  173.  
  174. current_user.is_logged_in = 1;
  175. current_user.high_score = 0;
  176. current_user.total_games = 0;
  177.  
  178. printf("Logged in as: %s (%s)\n", current_user.username, current_user.provider);
  179. return 1;
  180. }
  181.  
  182. // Save user data to server (simulated)
  183. void save_user_data() {
  184. if (!current_user.is_logged_in || strcmp(current_user.provider, "guest") == 0) {
  185. return;
  186. }
  187.  
  188. printf("Saving user data to server...\n");
  189. printf("User: %s, High Score: %d, Games: %d\n",
  190. current_user.username, current_user.high_score, current_user.total_games);
  191.  
  192. // In real implementation, this would make HTTP POST to your game server
  193. // Example: POST /api/users/{user_id}/save with score data
  194. }
  195.  
  196. // Load user data from server (simulated)
  197. void load_user_data() {
  198. if (!current_user.is_logged_in || strcmp(current_user.provider, "guest") == 0) {
  199. return;
  200. }
  201.  
  202. printf("Loading user data from server...\n");
  203.  
  204. // Simulate loading saved data
  205. current_user.high_score = 1250; // Example saved high score
  206. current_user.total_games = 15; // Example games played
  207.  
  208. printf("Loaded: High Score: %d, Games Played: %d\n",
  209. current_user.high_score, current_user.total_games);
  210. }
  211.  
  212. // Draw text function (simplified)
  213. void draw_text(float x, float y, const char* text, float r, float g, float b) {
  214. glColor3f(r, g, b);
  215. glRasterPos2f(x, y);
  216. for (int i = 0; text[i] != '\0'; i++) {
  217. glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, text[i]);
  218. }
  219. }
  220.  
  221. // Draw login screen
  222. void draw_login_screen() {
  223. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  224.  
  225. // Set up 2D rendering
  226. glMatrixMode(GL_PROJECTION);
  227. glPushMatrix();
  228. glLoadIdentity();
  229. glOrtho(0, window_width, window_height, 0, -1, 1);
  230. glMatrixMode(GL_MODELVIEW);
  231. glPushMatrix();
  232. glLoadIdentity();
  233.  
  234. glDisable(GL_DEPTH_TEST);
  235.  
  236. // Background gradient
  237. glBegin(GL_QUADS);
  238. glColor3f(0.1f, 0.1f, 0.2f);
  239. glVertex2f(0, 0);
  240. glVertex2f(window_width, 0);
  241. glColor3f(0.2f, 0.1f, 0.3f);
  242. glVertex2f(window_width, window_height);
  243. glVertex2f(0, window_height);
  244. glEnd();
  245.  
  246. // Game title
  247. draw_text(250, 100, "OPEN WORLD COMBAT GAME", 1.0f, 1.0f, 1.0f);
  248. draw_text(300, 130, "Choose Login Method", 0.8f, 0.8f, 0.8f);
  249.  
  250. // Draw login buttons
  251. for (int i = 0; i < 3; i++) {
  252. LoginButton* btn = &login_buttons[i];
  253.  
  254. // Button background
  255. glColor3f(btn->r, btn->g, btn->b);
  256. glBegin(GL_QUADS);
  257. glVertex2f(btn->x, btn->y);
  258. glVertex2f(btn->x + btn->width, btn->y);
  259. glVertex2f(btn->x + btn->width, btn->y + btn->height);
  260. glVertex2f(btn->x, btn->y + btn->height);
  261. glEnd();
  262.  
  263. // Button border
  264. glColor3f(1.0f, 1.0f, 1.0f);
  265. glLineWidth(2.0f);
  266. glBegin(GL_LINE_LOOP);
  267. glVertex2f(btn->x, btn->y);
  268. glVertex2f(btn->x + btn->width, btn->y);
  269. glVertex2f(btn->x + btn->width, btn->y + btn->height);
  270. glVertex2f(btn->x, btn->y + btn->height);
  271. glEnd();
  272.  
  273. // Button text
  274. draw_text(btn->x + 50, btn->y + 30, btn->text, 1.0f, 1.0f, 1.0f);
  275. }
  276.  
  277. // Instructions
  278. draw_text(200, 500, "Click on a button to login and start playing!", 0.7f, 0.7f, 0.7f);
  279.  
  280. glEnable(GL_DEPTH_TEST);
  281. glPopMatrix();
  282. glMatrixMode(GL_PROJECTION);
  283. glPopMatrix();
  284. glMatrixMode(GL_MODELVIEW);
  285. }
  286. void init_game() {
  287. srand(time(NULL));
  288.  
  289. // Initialize enemies
  290. for (int i = 0; i < ENEMY_COUNT; i++) {
  291. enemies[i].x = (rand() % 40) - 20.0f;
  292. enemies[i].z = (rand() % 40) - 20.0f;
  293. enemies[i].y = 1.0f;
  294. enemies[i].rotation = rand() % 360;
  295. enemies[i].health = 50;
  296. enemies[i].active = 1;
  297. enemies[i].ai_timer = 0.0f;
  298. }
  299.  
  300. // Initialize projectiles
  301. for (int i = 0; i < MAX_PROJECTILES; i++) {
  302. projectiles[i].active = 0;
  303. }
  304. }
  305.  
  306. // Create a projectile
  307. void create_projectile(float x, float y, float z, float angle, int from_player) {
  308. for (int i = 0; i < MAX_PROJECTILES; i++) {
  309. if (!projectiles[i].active) {
  310. projectiles[i].x = x;
  311. projectiles[i].y = y;
  312. projectiles[i].z = z;
  313. projectiles[i].dx = sin(angle * M_PI / 180.0f) * PROJECTILE_SPEED;
  314. projectiles[i].dz = -cos(angle * M_PI / 180.0f) * PROJECTILE_SPEED;
  315. projectiles[i].dy = 0.0f;
  316. projectiles[i].active = 1;
  317. projectiles[i].from_player = from_player;
  318. break;
  319. }
  320. }
  321. }
  322.  
  323. // Draw a cube with gradients
  324. void draw_gradient_cube(float size, float r1, float g1, float b1, float r2, float g2, float b2) {
  325. glBegin(GL_QUADS);
  326.  
  327. // Front face (gradient)
  328. glColor3f(r1, g1, b1); glVertex3f(-size, -size, size);
  329. glColor3f(r1, g1, b1); glVertex3f(size, -size, size);
  330. glColor3f(r2, g2, b2); glVertex3f(size, size, size);
  331. glColor3f(r2, g2, b2); glVertex3f(-size, size, size);
  332.  
  333. // Back face
  334. glColor3f(r1*0.7f, g1*0.7f, b1*0.7f); glVertex3f(-size, -size, -size);
  335. glColor3f(r1*0.7f, g1*0.7f, b1*0.7f); glVertex3f(-size, size, -size);
  336. glColor3f(r2*0.7f, g2*0.7f, b2*0.7f); glVertex3f(size, size, -size);
  337. glColor3f(r2*0.7f, g2*0.7f, b2*0.7f); glVertex3f(size, -size, -size);
  338.  
  339. // Top face
  340. glColor3f(r2, g2, b2); glVertex3f(-size, size, -size);
  341. glColor3f(r2, g2, b2); glVertex3f(-size, size, size);
  342. glColor3f(r2, g2, b2); glVertex3f(size, size, size);
  343. glColor3f(r2, g2, b2); glVertex3f(size, size, -size);
  344.  
  345. // Bottom face
  346. glColor3f(r1*0.5f, g1*0.5f, b1*0.5f); glVertex3f(-size, -size, -size);
  347. glColor3f(r1*0.5f, g1*0.5f, b1*0.5f); glVertex3f(size, -size, -size);
  348. glColor3f(r1*0.5f, g1*0.5f, b1*0.5f); glVertex3f(size, -size, size);
  349. glColor3f(r1*0.5f, g1*0.5f, b1*0.5f); glVertex3f(-size, -size, size);
  350.  
  351. // Right face
  352. glColor3f(r1*0.8f, g1*0.8f, b1*0.8f); glVertex3f(size, -size, -size);
  353. glColor3f(r2*0.8f, g2*0.8f, b2*0.8f); glVertex3f(size, size, -size);
  354. glColor3f(r2*0.8f, g2*0.8f, b2*0.8f); glVertex3f(size, size, size);
  355. glColor3f(r1*0.8f, g1*0.8f, b1*0.8f); glVertex3f(size, -size, size);
  356.  
  357. // Left face
  358. glColor3f(r1*0.8f, g1*0.8f, b1*0.8f); glVertex3f(-size, -size, -size);
  359. glColor3f(r1*0.8f, g1*0.8f, b1*0.8f); glVertex3f(-size, -size, size);
  360. glColor3f(r2*0.8f, g2*0.8f, b2*0.8f); glVertex3f(-size, size, size);
  361. glColor3f(r2*0.8f, g2*0.8f, b2*0.8f); glVertex3f(-size, size, -size);
  362.  
  363. glEnd();
  364. }
  365.  
  366. // Draw the terrain
  367. void draw_terrain() {
  368. glColor3f(0.2f, 0.6f, 0.2f);
  369. glBegin(GL_QUADS);
  370. for (int x = -WORLD_SIZE; x < WORLD_SIZE; x += 2) {
  371. for (int z = -WORLD_SIZE; z < WORLD_SIZE; z += 2) {
  372. float height1 = sin(x * 0.1f) * cos(z * 0.1f) * 0.5f;
  373. float height2 = sin((x+2) * 0.1f) * cos(z * 0.1f) * 0.5f;
  374. float height3 = sin((x+2) * 0.1f) * cos((z+2) * 0.1f) * 0.5f;
  375. float height4 = sin(x * 0.1f) * cos((z+2) * 0.1f) * 0.5f;
  376.  
  377. glColor3f(0.2f + height1*0.2f, 0.6f + height1*0.1f, 0.2f);
  378. glVertex3f(x, height1, z);
  379. glColor3f(0.2f + height2*0.2f, 0.6f + height2*0.1f, 0.2f);
  380. glVertex3f(x+2, height2, z);
  381. glColor3f(0.2f + height3*0.2f, 0.6f + height3*0.1f, 0.2f);
  382. glVertex3f(x+2, height3, z+2);
  383. glColor3f(0.2f + height4*0.2f, 0.6f + height4*0.1f, 0.2f);
  384. glVertex3f(x, height4, z+2);
  385. }
  386. }
  387. glEnd();
  388. }
  389.  
  390. // Draw player
  391. void draw_player() {
  392. glPushMatrix();
  393. glTranslatef(player.x, player.y, player.z);
  394. glRotatef(player.rotation, 0, 1, 0);
  395.  
  396. // Player body (blue gradient)
  397. draw_gradient_cube(0.5f, 0.3f, 0.3f, 1.0f, 0.6f, 0.6f, 1.0f);
  398.  
  399. // Player weapon
  400. glPushMatrix();
  401. glTranslatef(0.7f, 0.2f, 0.0f);
  402. glScalef(0.8f, 0.1f, 0.1f);
  403. draw_gradient_cube(0.3f, 0.8f, 0.8f, 0.8f, 0.5f, 0.5f, 0.5f);
  404. glPopMatrix();
  405.  
  406. glPopMatrix();
  407. }
  408.  
  409. // Draw enemies
  410. void draw_enemies() {
  411. for (int i = 0; i < ENEMY_COUNT; i++) {
  412. if (enemies[i].active) {
  413. glPushMatrix();
  414. glTranslatef(enemies[i].x, enemies[i].y, enemies[i].z);
  415. glRotatef(enemies[i].rotation, 0, 1, 0);
  416.  
  417. // Enemy body (red gradient)
  418. draw_gradient_cube(0.4f, 1.0f, 0.2f, 0.2f, 0.6f, 0.1f, 0.1f);
  419.  
  420. glPopMatrix();
  421. }
  422. }
  423. }
  424.  
  425. // Draw projectiles
  426. void draw_projectiles() {
  427. for (int i = 0; i < MAX_PROJECTILES; i++) {
  428. if (projectiles[i].active) {
  429. glPushMatrix();
  430. glTranslatef(projectiles[i].x, projectiles[i].y, projectiles[i].z);
  431.  
  432. if (projectiles[i].from_player) {
  433. glColor3f(0.0f, 1.0f, 1.0f); // Cyan for player projectiles
  434. } else {
  435. glColor3f(1.0f, 0.5f, 0.0f); // Orange for enemy projectiles
  436. }
  437.  
  438. glutSolidSphere(0.1f, 8, 8);
  439. glPopMatrix();
  440. }
  441. }
  442. }
  443.  
  444. // Draw skybox
  445. void draw_skybox() {
  446. glDisable(GL_DEPTH_TEST);
  447. glPushMatrix();
  448. glLoadIdentity();
  449.  
  450. // Create a gradient sky
  451. glBegin(GL_QUADS);
  452. // Sky gradient from horizon to zenith
  453. glColor3f(0.6f, 0.8f, 1.0f); // Light blue at horizon
  454. glVertex3f(-50, -50, -50);
  455. glVertex3f(50, -50, -50);
  456. glColor3f(0.2f, 0.4f, 0.8f); // Darker blue at top
  457. glVertex3f(50, 50, -50);
  458. glVertex3f(-50, 50, -50);
  459. glEnd();
  460.  
  461. glPopMatrix();
  462. glEnable(GL_DEPTH_TEST);
  463. }
  464.  
  465. // Draw HUD with user info
  466. void draw_hud() {
  467. glMatrixMode(GL_PROJECTION);
  468. glPushMatrix();
  469. glLoadIdentity();
  470. glOrtho(0, window_width, window_height, 0, -1, 1);
  471. glMatrixMode(GL_MODELVIEW);
  472. glPushMatrix();
  473. glLoadIdentity();
  474.  
  475. glDisable(GL_DEPTH_TEST);
  476.  
  477. // Health bar background
  478. glColor3f(0.2f, 0.2f, 0.2f);
  479. glBegin(GL_QUADS);
  480. glVertex2f(10, 10);
  481. glVertex2f(210, 10);
  482. glVertex2f(210, 30);
  483. glVertex2f(10, 30);
  484. glEnd();
  485.  
  486. // Health bar
  487. glColor3f(1.0f, 0.0f, 0.0f);
  488. glBegin(GL_QUADS);
  489. glVertex2f(10, 10);
  490. glVertex2f(10 + (player.health * 2), 10);
  491. glVertex2f(10 + (player.health * 2), 30);
  492. glVertex2f(10, 30);
  493. glEnd();
  494.  
  495. // User info panel
  496. glColor3f(0.0f, 0.0f, 0.0f);
  497. glBegin(GL_QUADS);
  498. glVertex2f(window_width - 250, 10);
  499. glVertex2f(window_width - 10, 10);
  500. glVertex2f(window_width - 10, 120);
  501. glVertex2f(window_width - 250, 120);
  502. glEnd();
  503.  
  504. // User info text
  505. char score_text[50], high_score_text[50], user_text[100];
  506. sprintf(score_text, "Score: %d", player.score);
  507. sprintf(high_score_text, "High Score: %d", current_user.high_score);
  508. sprintf(user_text, "Player: %s", current_user.username);
  509.  
  510. draw_text(window_width - 240, 30, user_text, 1.0f, 1.0f, 1.0f);
  511. draw_text(window_width - 240, 50, score_text, 0.8f, 1.0f, 0.8f);
  512. draw_text(window_width - 240, 70, high_score_text, 1.0f, 0.8f, 0.2f);
  513.  
  514. if (current_user.is_logged_in && strcmp(current_user.provider, "guest") != 0) {
  515. draw_text(window_width - 240, 90, "Data will be saved", 0.6f, 0.8f, 1.0f);
  516. }
  517.  
  518. // Controls reminder
  519. draw_text(10, window_height - 60, "WASD: Move | Space: Shoot | Mouse: Camera", 0.7f, 0.7f, 0.7f);
  520. draw_text(10, window_height - 40, "ESC: Back to Login", 0.7f, 0.7f, 0.7f);
  521.  
  522. glEnable(GL_DEPTH_TEST);
  523.  
  524. glPopMatrix();
  525. glMatrixMode(GL_PROJECTION);
  526. glPopMatrix();
  527. glMatrixMode(GL_MODELVIEW);
  528. }
  529.  
  530. // Update game logic
  531. void update_game() {
  532. if (game_state != GAME_STATE_PLAYING) return;
  533.  
  534. time_counter += 0.016f; // Assume 60 FPS
  535.  
  536. // Update weapon cooldown
  537. if (player.weapon_cooldown > 0) {
  538. player.weapon_cooldown -= 0.016f;
  539. }
  540.  
  541. // Update projectiles
  542. for (int i = 0; i < MAX_PROJECTILES; i++) {
  543. if (projectiles[i].active) {
  544. projectiles[i].x += projectiles[i].dx;
  545. projectiles[i].y += projectiles[i].dy;
  546. projectiles[i].z += projectiles[i].dz;
  547.  
  548. // Remove projectiles that are out of bounds
  549. if (fabs(projectiles[i].x) > WORLD_SIZE || fabs(projectiles[i].z) > WORLD_SIZE) {
  550. projectiles[i].active = 0;
  551. }
  552.  
  553. // Check collision with enemies (if from player)
  554. if (projectiles[i].from_player) {
  555. for (int j = 0; j < ENEMY_COUNT; j++) {
  556. if (enemies[j].active) {
  557. float dx = projectiles[i].x - enemies[j].x;
  558. float dz = projectiles[i].z - enemies[j].z;
  559. if (sqrt(dx*dx + dz*dz) < 1.0f) {
  560. enemies[j].health -= 25;
  561. projectiles[i].active = 0;
  562. player.score += 10;
  563. if (enemies[j].health <= 0) {
  564. enemies[j].active = 0;
  565. player.score += 50;
  566. }
  567. break;
  568. }
  569. }
  570. }
  571. }
  572. // Check collision with player (if from enemy)
  573. else {
  574. float dx = projectiles[i].x - player.x;
  575. float dz = projectiles[i].z - player.z;
  576. if (sqrt(dx*dx + dz*dz) < 1.0f) {
  577. player.health -= 10;
  578. projectiles[i].active = 0;
  579. if (player.health <= 0) {
  580. // Game over - save score if better than high score
  581. if (player.score > current_user.high_score) {
  582. current_user.high_score = player.score;
  583. printf("New High Score: %d!\n", current_user.high_score);
  584. }
  585. current_user.total_games++;
  586. save_user_data();
  587.  
  588. printf("Game Over! Final Score: %d\n", player.score);
  589. player.health = 100;
  590. player.score = 0;
  591. init_game(); // Restart
  592. }
  593. }
  594. }
  595. }
  596. }
  597.  
  598. // Update enemies AI
  599. for (int i = 0; i < ENEMY_COUNT; i++) {
  600. if (enemies[i].active) {
  601. enemies[i].ai_timer += 0.016f;
  602.  
  603. // Move towards player
  604. float dx = player.x - enemies[i].x;
  605. float dz = player.z - enemies[i].z;
  606. float distance = sqrt(dx*dx + dz*dz);
  607.  
  608. if (distance > 2.0f) {
  609. enemies[i].x += (dx / distance) * 0.05f;
  610. enemies[i].z += (dz / distance) * 0.05f;
  611. }
  612.  
  613. // Rotate to face player
  614. enemies[i].rotation = atan2(dx, -dz) * 180.0f / M_PI;
  615.  
  616. // Shoot at player occasionally
  617. if (enemies[i].ai_timer > 2.0f && distance < 15.0f) {
  618. create_projectile(enemies[i].x, enemies[i].y, enemies[i].z, enemies[i].rotation, 0);
  619. enemies[i].ai_timer = 0.0f;
  620. }
  621. }
  622. }
  623.  
  624. // Respawn enemies if all are defeated
  625. int active_enemies = 0;
  626. for (int i = 0; i < ENEMY_COUNT; i++) {
  627. if (enemies[i].active) active_enemies++;
  628. }
  629. if (active_enemies == 0) {
  630. for (int i = 0; i < ENEMY_COUNT; i++) {
  631. enemies[i].x = (rand() % 40) - 20.0f;
  632. enemies[i].z = (rand() % 40) - 20.0f;
  633. enemies[i].health = 50 + (player.score / 100) * 10; // Increase difficulty
  634. enemies[i].active = 1;
  635. }
  636. player.score += 100;
  637. }
  638. }
  639.  
  640. // Handle movement
  641. void handle_movement() {
  642. if (game_state != GAME_STATE_PLAYING) return;
  643.  
  644. float move_speed = PLAYER_SPEED;
  645.  
  646. if (keys['w'] || keys['W']) {
  647. player.x += sin(player.rotation * M_PI / 180.0f) * move_speed;
  648. player.z -= cos(player.rotation * M_PI / 180.0f) * move_speed;
  649. }
  650. if (keys['s'] || keys['S']) {
  651. player.x -= sin(player.rotation * M_PI / 180.0f) * move_speed;
  652. player.z += cos(player.rotation * M_PI / 180.0f) * move_speed;
  653. }
  654. if (keys['a'] || keys['A']) {
  655. player.rotation -= 3.0f;
  656. }
  657. if (keys['d'] || keys['D']) {
  658. player.rotation += 3.0f;
  659. }
  660.  
  661. // Keep player in bounds
  662. if (player.x > WORLD_SIZE) player.x = WORLD_SIZE;
  663. if (player.x < -WORLD_SIZE) player.x = -WORLD_SIZE;
  664. if (player.z > WORLD_SIZE) player.z = WORLD_SIZE;
  665. if (player.z < -WORLD_SIZE) player.z = -WORLD_SIZE;
  666.  
  667. // Shooting
  668. if ((keys[' '] || keys[32]) && player.weapon_cooldown <= 0) {
  669. create_projectile(player.x, player.y, player.z, player.rotation, 1);
  670. player.weapon_cooldown = 0.2f; // 200ms cooldown
  671. }
  672. } WORLD_SIZE) player.x = WORLD_SIZE;
  673. if (player.x < -WORLD_SIZE) player.x = -WORLD_SIZE;
  674. if (player.z > WORLD_SIZE) player.z = WORLD_SIZE;
  675. if (player.z < -WORLD_SIZE) player.z = -WORLD_SIZE;
  676.  
  677. // Shooting
  678. if ((keys[' '] || keys[32]) && player.weapon_cooldown <= 0) {
  679. create_projectile(player.x, player.y, player.z, player.rotation, 1);
  680. player.weapon_cooldown = 0.2f; // 200ms cooldown
  681. }
  682. }
  683.  
  684. // Display function
  685. void display() {
  686. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  687. glLoadIdentity();
  688.  
  689. // Set up camera
  690. float cam_x = player.x + camera_distance * sin(camera_angle_y * M_PI / 180.0f) * cos(camera_angle_x * M_PI / 180.0f);
  691. float cam_y = player.y + camera_distance * sin(camera_angle_x * M_PI / 180.0f);
  692. float cam_z = player.z + camera_distance * cos(camera_angle_y * M_PI / 180.0f) * cos(camera_angle_x * M_PI / 180.0f);
  693.  
  694. gluLookAt(cam_x, cam_y, cam_z, player.x, player.y, player.z, 0, 1, 0);
  695.  
  696. // Enable lighting
  697. glEnable(GL_LIGHTING);
  698. glEnable(GL_LIGHT0);
  699.  
  700. float light_pos[] = {10.0f, 20.0f, 10.0f, 1.0f};
  701. float light_color[] = {1.0f, 1.0f, 0.9f, 1.0f};
  702. float ambient[] = {0.3f, 0.3f, 0.4f, 1.0f};
  703.  
  704. glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
  705. glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);
  706. glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
  707.  
  708. draw_skybox();
  709. draw_terrain();
  710. draw_player();
  711. draw_enemies();
  712.  
  713. glDisable(GL_LIGHTING);
  714. draw_projectiles();
  715. draw_hud();
  716.  
  717. glutSwapBuffers();
  718. }
  719.  
  720. // Keyboard input
  721. void keyboard(unsigned char key, int x, int y) {
  722. keys[key] = 1;
  723. if (key == 27) exit(0); // ESC to quit
  724. }
  725.  
  726. void keyboard_up(unsigned char key, int x, int y) {
  727. keys[key] = 0;
  728. }
  729.  
  730. // Mouse input for camera control
  731. void mouse_motion(int x, int y) {
  732. if (mouse_x != -1) {
  733. camera_angle_y += (x - mouse_x) * 0.5f;
  734. camera_angle_x += (y - mouse_y) * 0.5f;
  735.  
  736. if (camera_angle_x > 80.0f) camera_angle_x = 80.0f;
  737. if (camera_angle_x < -80.0f) camera_angle_x = -80.0f;
  738. }
  739. mouse_x = x;
  740. mouse_y = y;
  741. }
  742.  
  743. // Timer function for animation
  744. void timer(int value) {
  745. handle_movement();
  746. update_game();
  747. glutPostRedisplay();
  748. glutTimerFunc(16, timer, 0); // 60 FPS
  749. }
  750.  
  751. // Reshape function
  752. void reshape(int w, int h) {
  753. glViewport(0, 0, w, h);
  754. glMatrixMode(GL_PROJECTION);
  755. glLoadIdentity();
  756. gluPerspective(45.0, (float)w/h, 0.1, 1000.0);
  757. glMatrixMode(GL_MODELVIEW);
  758. }
  759.  
  760. // Initialize OpenGL
  761. void init_opengl() {
  762. glEnable(GL_DEPTH_TEST);
  763. glEnable(GL_BLEND);
  764. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  765. glEnable(GL_COLOR_MATERIAL);
  766. glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
  767. glClearColor(0.5f, 0.7f, 1.0f, 1.0f);
  768.  
  769. mouse_x = mouse_y = -1;
  770. }
  771.  
  772. int main(int argc, char** argv) {
  773. printf("=== Open World Combat Game ===\n");
  774. printf("Controls:\n");
  775. printf("W/S - Move Forward/Backward\n");
  776. printf("A/D - Turn Left/Right\n");
  777. printf("Space - Shoot\n");
  778. printf("Mouse - Control Camera\n");
  779. printf("ESC - Quit\n\n");
  780.  
  781. glutInit(&argc, argv);
  782. glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  783. glutInitWindowSize(800, 600);
  784. glutCreateWindow("Open World Combat Game");
  785.  
  786. init_opengl();
  787. init_game();
  788.  
  789. glutDisplayFunc(display);
  790. glutReshapeFunc(reshape);
  791. glutKeyboardFunc(keyboard);
  792. glutKeyboardUpFunc(keyboard_up);
  793. glutPassiveMotionFunc(mouse_motion);
  794. glutMotionFunc(mouse_motion);
  795. glutTimerFunc(0, timer, 0);
  796.  
  797. printf("Game started! Defend yourself against the red enemies!\n");
  798.  
  799. glutMainLoop();
  800. return 0;
  801. }
Success #stdin #stdout 0.02s 26204KB
stdin
Standard input is empty
stdout
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>

#ifdef _WIN32
    #include <windows.h>
    #include <GL/gl.h>
    #include <GL/glu.h>
    #include <GL/glut.h>
    #include <wininet.h>
    #pragma comment(lib, "wininet.lib")
#else
    #include <OpenGL/gl.h>
    #include <OpenGL/glu.h>
    #include <GLUT/glut.h>
    #include <curl/curl.h>
#endif

// Game constants
#define WORLD_SIZE 50.0f
#define PLAYER_SPEED 0.2f
#define ENEMY_COUNT 5
#define MAX_PROJECTILES 20
#define PROJECTILE_SPEED 0.5f
#define MAX_USERNAME 50
#define MAX_EMAIL 100

// Game states
typedef enum {
    GAME_STATE_LOGIN,
    GAME_STATE_PLAYING,
    GAME_STATE_MENU
} GameState;

// User authentication structure
typedef struct {
    char username[MAX_USERNAME];
    char email[MAX_EMAIL];
    char provider[20]; // "facebook", "gmail", or "guest"
    int user_id;
    int is_logged_in;
    int high_score;
    int total_games;
} User;

// Login button structure
typedef struct {
    float x, y, width, height;
    char text[50];
    float r, g, b;
    int provider_type; // 0=facebook, 1=gmail, 2=guest
} LoginButton;

// Player structure
typedef struct {
    float x, y, z;
    float rotation;
    int health;
    int score;
    float weapon_cooldown;
} Player;

// Enemy structure
typedef struct {
    float x, y, z;
    float rotation;
    int health;
    int active;
    float ai_timer;
} Enemy;

// Projectile structure
typedef struct {
    float x, y, z;
    float dx, dy, dz;
    int active;
    int from_player;
} Projectile;

// Global game state
Player player = {0.0f, 1.0f, 0.0f, 0.0f, 100, 0, 0.0f};
Enemy enemies[ENEMY_COUNT];
Projectile projectiles[MAX_PROJECTILES];
User current_user = {"", "", "", 0, 0, 0, 0};
GameState game_state = GAME_STATE_LOGIN;
LoginButton login_buttons[3];
float camera_angle_x = 30.0f;
float camera_angle_y = 0.0f;
float camera_distance = 15.0f;
int keys[256] = {0};
int mouse_x, mouse_y;
float time_counter = 0.0f;
int window_width = 800, window_height = 600;

// HTTP response structure for API calls
typedef struct {
    char *data;
    size_t size;
} HTTPResponse;

// Write callback for HTTP requests
size_t write_callback(void *contents, size_t size, size_t nmemb, HTTPResponse *response) {
    size_t real_size = size * nmemb;
    char *ptr = realloc(response->data, response->size + real_size + 1);
    if (ptr == NULL) {
        printf("Not enough memory (realloc returned NULL)\n");
        return 0;
    }
    response->data = ptr;
    memcpy(&(response->data[response->size]), contents, real_size);
    response->size += real_size;
    response->data[response->size] = 0;
    return real_size;
}

// Initialize login system
void init_login_system() {
    // Facebook login button
    login_buttons[0].x = 250;
    login_buttons[0].y = 200;
    login_buttons[0].width = 300;
    login_buttons[0].height = 50;
    strcpy(login_buttons[0].text, "Login with Facebook");
    login_buttons[0].r = 0.23f; login_buttons[0].g = 0.35f; login_buttons[0].b = 0.60f;
    login_buttons[0].provider_type = 0;
    
    // Gmail login button
    login_buttons[1].x = 250;
    login_buttons[1].y = 280;
    login_buttons[1].width = 300;
    login_buttons[1].height = 50;
    strcpy(login_buttons[1].text, "Login with Gmail");
    login_buttons[1].r = 0.85f; login_buttons[1].g = 0.26f; login_buttons[1].b = 0.21f;
    login_buttons[1].provider_type = 1;
    
    // Guest login button
    login_buttons[2].x = 250;
    login_buttons[2].y = 360;
    login_buttons[2].width = 300;
    login_buttons[2].height = 50;
    strcpy(login_buttons[2].text, "Play as Guest");
    login_buttons[2].r = 0.5f; login_buttons[2].g = 0.5f; login_buttons[2].b = 0.5f;
    login_buttons[2].provider_type = 2;
}

// Simulate OAuth authentication (in real implementation, this would open browser)
int authenticate_with_provider(int provider_type) {
    switch(provider_type) {
        case 0: // Facebook
            printf("Opening Facebook OAuth... (simulated)\n");
            strcpy(current_user.username, "Facebook User");
            strcpy(current_user.email, "user@facebook.com");
            strcpy(current_user.provider, "facebook");
            current_user.user_id = 12345;
            break;
        case 1: // Gmail
            printf("Opening Google OAuth... (simulated)\n");
            strcpy(current_user.username, "Gmail User");
            strcpy(current_user.email, "user@gmail.com");
            strcpy(current_user.provider, "gmail");
            current_user.user_id = 67890;
            break;
        case 2: // Guest
            printf("Playing as guest...\n");
            strcpy(current_user.username, "Guest");
            strcpy(current_user.email, "");
            strcpy(current_user.provider, "guest");
            current_user.user_id = rand() % 10000;
            break;
    }
    
    current_user.is_logged_in = 1;
    current_user.high_score = 0;
    current_user.total_games = 0;
    
    printf("Logged in as: %s (%s)\n", current_user.username, current_user.provider);
    return 1;
}

// Save user data to server (simulated)
void save_user_data() {
    if (!current_user.is_logged_in || strcmp(current_user.provider, "guest") == 0) {
        return;
    }
    
    printf("Saving user data to server...\n");
    printf("User: %s, High Score: %d, Games: %d\n", 
           current_user.username, current_user.high_score, current_user.total_games);
    
    // In real implementation, this would make HTTP POST to your game server
    // Example: POST /api/users/{user_id}/save with score data
}

// Load user data from server (simulated)
void load_user_data() {
    if (!current_user.is_logged_in || strcmp(current_user.provider, "guest") == 0) {
        return;
    }
    
    printf("Loading user data from server...\n");
    
    // Simulate loading saved data
    current_user.high_score = 1250; // Example saved high score
    current_user.total_games = 15;  // Example games played
    
    printf("Loaded: High Score: %d, Games Played: %d\n", 
           current_user.high_score, current_user.total_games);
}

// Draw text function (simplified)
void draw_text(float x, float y, const char* text, float r, float g, float b) {
    glColor3f(r, g, b);
    glRasterPos2f(x, y);
    for (int i = 0; text[i] != '\0'; i++) {
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, text[i]);
    }
}

// Draw login screen
void draw_login_screen() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    // Set up 2D rendering
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glOrtho(0, window_width, window_height, 0, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
    
    glDisable(GL_DEPTH_TEST);
    
    // Background gradient
    glBegin(GL_QUADS);
    glColor3f(0.1f, 0.1f, 0.2f);
    glVertex2f(0, 0);
    glVertex2f(window_width, 0);
    glColor3f(0.2f, 0.1f, 0.3f);
    glVertex2f(window_width, window_height);
    glVertex2f(0, window_height);
    glEnd();
    
    // Game title
    draw_text(250, 100, "OPEN WORLD COMBAT GAME", 1.0f, 1.0f, 1.0f);
    draw_text(300, 130, "Choose Login Method", 0.8f, 0.8f, 0.8f);
    
    // Draw login buttons
    for (int i = 0; i < 3; i++) {
        LoginButton* btn = &login_buttons[i];
        
        // Button background
        glColor3f(btn->r, btn->g, btn->b);
        glBegin(GL_QUADS);
        glVertex2f(btn->x, btn->y);
        glVertex2f(btn->x + btn->width, btn->y);
        glVertex2f(btn->x + btn->width, btn->y + btn->height);
        glVertex2f(btn->x, btn->y + btn->height);
        glEnd();
        
        // Button border
        glColor3f(1.0f, 1.0f, 1.0f);
        glLineWidth(2.0f);
        glBegin(GL_LINE_LOOP);
        glVertex2f(btn->x, btn->y);
        glVertex2f(btn->x + btn->width, btn->y);
        glVertex2f(btn->x + btn->width, btn->y + btn->height);
        glVertex2f(btn->x, btn->y + btn->height);
        glEnd();
        
        // Button text
        draw_text(btn->x + 50, btn->y + 30, btn->text, 1.0f, 1.0f, 1.0f);
    }
    
    // Instructions
    draw_text(200, 500, "Click on a button to login and start playing!", 0.7f, 0.7f, 0.7f);
    
    glEnable(GL_DEPTH_TEST);
    glPopMatrix();
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
}
void init_game() {
    srand(time(NULL));
    
    // Initialize enemies
    for (int i = 0; i < ENEMY_COUNT; i++) {
        enemies[i].x = (rand() % 40) - 20.0f;
        enemies[i].z = (rand() % 40) - 20.0f;
        enemies[i].y = 1.0f;
        enemies[i].rotation = rand() % 360;
        enemies[i].health = 50;
        enemies[i].active = 1;
        enemies[i].ai_timer = 0.0f;
    }
    
    // Initialize projectiles
    for (int i = 0; i < MAX_PROJECTILES; i++) {
        projectiles[i].active = 0;
    }
}

// Create a projectile
void create_projectile(float x, float y, float z, float angle, int from_player) {
    for (int i = 0; i < MAX_PROJECTILES; i++) {
        if (!projectiles[i].active) {
            projectiles[i].x = x;
            projectiles[i].y = y;
            projectiles[i].z = z;
            projectiles[i].dx = sin(angle * M_PI / 180.0f) * PROJECTILE_SPEED;
            projectiles[i].dz = -cos(angle * M_PI / 180.0f) * PROJECTILE_SPEED;
            projectiles[i].dy = 0.0f;
            projectiles[i].active = 1;
            projectiles[i].from_player = from_player;
            break;
        }
    }
}

// Draw a cube with gradients
void draw_gradient_cube(float size, float r1, float g1, float b1, float r2, float g2, float b2) {
    glBegin(GL_QUADS);
    
    // Front face (gradient)
    glColor3f(r1, g1, b1); glVertex3f(-size, -size, size);
    glColor3f(r1, g1, b1); glVertex3f(size, -size, size);
    glColor3f(r2, g2, b2); glVertex3f(size, size, size);
    glColor3f(r2, g2, b2); glVertex3f(-size, size, size);
    
    // Back face
    glColor3f(r1*0.7f, g1*0.7f, b1*0.7f); glVertex3f(-size, -size, -size);
    glColor3f(r1*0.7f, g1*0.7f, b1*0.7f); glVertex3f(-size, size, -size);
    glColor3f(r2*0.7f, g2*0.7f, b2*0.7f); glVertex3f(size, size, -size);
    glColor3f(r2*0.7f, g2*0.7f, b2*0.7f); glVertex3f(size, -size, -size);
    
    // Top face
    glColor3f(r2, g2, b2); glVertex3f(-size, size, -size);
    glColor3f(r2, g2, b2); glVertex3f(-size, size, size);
    glColor3f(r2, g2, b2); glVertex3f(size, size, size);
    glColor3f(r2, g2, b2); glVertex3f(size, size, -size);
    
    // Bottom face
    glColor3f(r1*0.5f, g1*0.5f, b1*0.5f); glVertex3f(-size, -size, -size);
    glColor3f(r1*0.5f, g1*0.5f, b1*0.5f); glVertex3f(size, -size, -size);
    glColor3f(r1*0.5f, g1*0.5f, b1*0.5f); glVertex3f(size, -size, size);
    glColor3f(r1*0.5f, g1*0.5f, b1*0.5f); glVertex3f(-size, -size, size);
    
    // Right face
    glColor3f(r1*0.8f, g1*0.8f, b1*0.8f); glVertex3f(size, -size, -size);
    glColor3f(r2*0.8f, g2*0.8f, b2*0.8f); glVertex3f(size, size, -size);
    glColor3f(r2*0.8f, g2*0.8f, b2*0.8f); glVertex3f(size, size, size);
    glColor3f(r1*0.8f, g1*0.8f, b1*0.8f); glVertex3f(size, -size, size);
    
    // Left face
    glColor3f(r1*0.8f, g1*0.8f, b1*0.8f); glVertex3f(-size, -size, -size);
    glColor3f(r1*0.8f, g1*0.8f, b1*0.8f); glVertex3f(-size, -size, size);
    glColor3f(r2*0.8f, g2*0.8f, b2*0.8f); glVertex3f(-size, size, size);
    glColor3f(r2*0.8f, g2*0.8f, b2*0.8f); glVertex3f(-size, size, -size);
    
    glEnd();
}

// Draw the terrain
void draw_terrain() {
    glColor3f(0.2f, 0.6f, 0.2f);
    glBegin(GL_QUADS);
    for (int x = -WORLD_SIZE; x < WORLD_SIZE; x += 2) {
        for (int z = -WORLD_SIZE; z < WORLD_SIZE; z += 2) {
            float height1 = sin(x * 0.1f) * cos(z * 0.1f) * 0.5f;
            float height2 = sin((x+2) * 0.1f) * cos(z * 0.1f) * 0.5f;
            float height3 = sin((x+2) * 0.1f) * cos((z+2) * 0.1f) * 0.5f;
            float height4 = sin(x * 0.1f) * cos((z+2) * 0.1f) * 0.5f;
            
            glColor3f(0.2f + height1*0.2f, 0.6f + height1*0.1f, 0.2f);
            glVertex3f(x, height1, z);
            glColor3f(0.2f + height2*0.2f, 0.6f + height2*0.1f, 0.2f);
            glVertex3f(x+2, height2, z);
            glColor3f(0.2f + height3*0.2f, 0.6f + height3*0.1f, 0.2f);
            glVertex3f(x+2, height3, z+2);
            glColor3f(0.2f + height4*0.2f, 0.6f + height4*0.1f, 0.2f);
            glVertex3f(x, height4, z+2);
        }
    }
    glEnd();
}

// Draw player
void draw_player() {
    glPushMatrix();
    glTranslatef(player.x, player.y, player.z);
    glRotatef(player.rotation, 0, 1, 0);
    
    // Player body (blue gradient)
    draw_gradient_cube(0.5f, 0.3f, 0.3f, 1.0f, 0.6f, 0.6f, 1.0f);
    
    // Player weapon
    glPushMatrix();
    glTranslatef(0.7f, 0.2f, 0.0f);
    glScalef(0.8f, 0.1f, 0.1f);
    draw_gradient_cube(0.3f, 0.8f, 0.8f, 0.8f, 0.5f, 0.5f, 0.5f);
    glPopMatrix();
    
    glPopMatrix();
}

// Draw enemies
void draw_enemies() {
    for (int i = 0; i < ENEMY_COUNT; i++) {
        if (enemies[i].active) {
            glPushMatrix();
            glTranslatef(enemies[i].x, enemies[i].y, enemies[i].z);
            glRotatef(enemies[i].rotation, 0, 1, 0);
            
            // Enemy body (red gradient)
            draw_gradient_cube(0.4f, 1.0f, 0.2f, 0.2f, 0.6f, 0.1f, 0.1f);
            
            glPopMatrix();
        }
    }
}

// Draw projectiles
void draw_projectiles() {
    for (int i = 0; i < MAX_PROJECTILES; i++) {
        if (projectiles[i].active) {
            glPushMatrix();
            glTranslatef(projectiles[i].x, projectiles[i].y, projectiles[i].z);
            
            if (projectiles[i].from_player) {
                glColor3f(0.0f, 1.0f, 1.0f); // Cyan for player projectiles
            } else {
                glColor3f(1.0f, 0.5f, 0.0f); // Orange for enemy projectiles
            }
            
            glutSolidSphere(0.1f, 8, 8);
            glPopMatrix();
        }
    }
}

// Draw skybox
void draw_skybox() {
    glDisable(GL_DEPTH_TEST);
    glPushMatrix();
    glLoadIdentity();
    
    // Create a gradient sky
    glBegin(GL_QUADS);
    // Sky gradient from horizon to zenith
    glColor3f(0.6f, 0.8f, 1.0f); // Light blue at horizon
    glVertex3f(-50, -50, -50);
    glVertex3f(50, -50, -50);
    glColor3f(0.2f, 0.4f, 0.8f); // Darker blue at top
    glVertex3f(50, 50, -50);
    glVertex3f(-50, 50, -50);
    glEnd();
    
    glPopMatrix();
    glEnable(GL_DEPTH_TEST);
}

// Draw HUD with user info
void draw_hud() {
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glOrtho(0, window_width, window_height, 0, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
    
    glDisable(GL_DEPTH_TEST);
    
    // Health bar background
    glColor3f(0.2f, 0.2f, 0.2f);
    glBegin(GL_QUADS);
    glVertex2f(10, 10);
    glVertex2f(210, 10);
    glVertex2f(210, 30);
    glVertex2f(10, 30);
    glEnd();
    
    // Health bar
    glColor3f(1.0f, 0.0f, 0.0f);
    glBegin(GL_QUADS);
    glVertex2f(10, 10);
    glVertex2f(10 + (player.health * 2), 10);
    glVertex2f(10 + (player.health * 2), 30);
    glVertex2f(10, 30);
    glEnd();
    
    // User info panel
    glColor3f(0.0f, 0.0f, 0.0f);
    glBegin(GL_QUADS);
    glVertex2f(window_width - 250, 10);
    glVertex2f(window_width - 10, 10);
    glVertex2f(window_width - 10, 120);
    glVertex2f(window_width - 250, 120);
    glEnd();
    
    // User info text
    char score_text[50], high_score_text[50], user_text[100];
    sprintf(score_text, "Score: %d", player.score);
    sprintf(high_score_text, "High Score: %d", current_user.high_score);
    sprintf(user_text, "Player: %s", current_user.username);
    
    draw_text(window_width - 240, 30, user_text, 1.0f, 1.0f, 1.0f);
    draw_text(window_width - 240, 50, score_text, 0.8f, 1.0f, 0.8f);
    draw_text(window_width - 240, 70, high_score_text, 1.0f, 0.8f, 0.2f);
    
    if (current_user.is_logged_in && strcmp(current_user.provider, "guest") != 0) {
        draw_text(window_width - 240, 90, "Data will be saved", 0.6f, 0.8f, 1.0f);
    }
    
    // Controls reminder
    draw_text(10, window_height - 60, "WASD: Move | Space: Shoot | Mouse: Camera", 0.7f, 0.7f, 0.7f);
    draw_text(10, window_height - 40, "ESC: Back to Login", 0.7f, 0.7f, 0.7f);
    
    glEnable(GL_DEPTH_TEST);
    
    glPopMatrix();
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
}

// Update game logic
void update_game() {
    if (game_state != GAME_STATE_PLAYING) return;
    
    time_counter += 0.016f; // Assume 60 FPS
    
    // Update weapon cooldown
    if (player.weapon_cooldown > 0) {
        player.weapon_cooldown -= 0.016f;
    }
    
    // Update projectiles
    for (int i = 0; i < MAX_PROJECTILES; i++) {
        if (projectiles[i].active) {
            projectiles[i].x += projectiles[i].dx;
            projectiles[i].y += projectiles[i].dy;
            projectiles[i].z += projectiles[i].dz;
            
            // Remove projectiles that are out of bounds
            if (fabs(projectiles[i].x) > WORLD_SIZE || fabs(projectiles[i].z) > WORLD_SIZE) {
                projectiles[i].active = 0;
            }
            
            // Check collision with enemies (if from player)
            if (projectiles[i].from_player) {
                for (int j = 0; j < ENEMY_COUNT; j++) {
                    if (enemies[j].active) {
                        float dx = projectiles[i].x - enemies[j].x;
                        float dz = projectiles[i].z - enemies[j].z;
                        if (sqrt(dx*dx + dz*dz) < 1.0f) {
                            enemies[j].health -= 25;
                            projectiles[i].active = 0;
                            player.score += 10;
                            if (enemies[j].health <= 0) {
                                enemies[j].active = 0;
                                player.score += 50;
                            }
                            break;
                        }
                    }
                }
            }
            // Check collision with player (if from enemy)
            else {
                float dx = projectiles[i].x - player.x;
                float dz = projectiles[i].z - player.z;
                if (sqrt(dx*dx + dz*dz) < 1.0f) {
                    player.health -= 10;
                    projectiles[i].active = 0;
                    if (player.health <= 0) {
                        // Game over - save score if better than high score
                        if (player.score > current_user.high_score) {
                            current_user.high_score = player.score;
                            printf("New High Score: %d!\n", current_user.high_score);
                        }
                        current_user.total_games++;
                        save_user_data();
                        
                        printf("Game Over! Final Score: %d\n", player.score);
                        player.health = 100;
                        player.score = 0;
                        init_game(); // Restart
                    }
                }
            }
        }
    }
    
    // Update enemies AI
    for (int i = 0; i < ENEMY_COUNT; i++) {
        if (enemies[i].active) {
            enemies[i].ai_timer += 0.016f;
            
            // Move towards player
            float dx = player.x - enemies[i].x;
            float dz = player.z - enemies[i].z;
            float distance = sqrt(dx*dx + dz*dz);
            
            if (distance > 2.0f) {
                enemies[i].x += (dx / distance) * 0.05f;
                enemies[i].z += (dz / distance) * 0.05f;
            }
            
            // Rotate to face player
            enemies[i].rotation = atan2(dx, -dz) * 180.0f / M_PI;
            
            // Shoot at player occasionally
            if (enemies[i].ai_timer > 2.0f && distance < 15.0f) {
                create_projectile(enemies[i].x, enemies[i].y, enemies[i].z, enemies[i].rotation, 0);
                enemies[i].ai_timer = 0.0f;
            }
        }
    }
    
    // Respawn enemies if all are defeated
    int active_enemies = 0;
    for (int i = 0; i < ENEMY_COUNT; i++) {
        if (enemies[i].active) active_enemies++;
    }
    if (active_enemies == 0) {
        for (int i = 0; i < ENEMY_COUNT; i++) {
            enemies[i].x = (rand() % 40) - 20.0f;
            enemies[i].z = (rand() % 40) - 20.0f;
            enemies[i].health = 50 + (player.score / 100) * 10; // Increase difficulty
            enemies[i].active = 1;
        }
        player.score += 100;
    }
}

// Handle movement
void handle_movement() {
    if (game_state != GAME_STATE_PLAYING) return;
    
    float move_speed = PLAYER_SPEED;
    
    if (keys['w'] || keys['W']) {
        player.x += sin(player.rotation * M_PI / 180.0f) * move_speed;
        player.z -= cos(player.rotation * M_PI / 180.0f) * move_speed;
    }
    if (keys['s'] || keys['S']) {
        player.x -= sin(player.rotation * M_PI / 180.0f) * move_speed;
        player.z += cos(player.rotation * M_PI / 180.0f) * move_speed;
    }
    if (keys['a'] || keys['A']) {
        player.rotation -= 3.0f;
    }
    if (keys['d'] || keys['D']) {
        player.rotation += 3.0f;
    }
    
    // Keep player in bounds
    if (player.x > WORLD_SIZE) player.x = WORLD_SIZE;
    if (player.x < -WORLD_SIZE) player.x = -WORLD_SIZE;
    if (player.z > WORLD_SIZE) player.z = WORLD_SIZE;
    if (player.z < -WORLD_SIZE) player.z = -WORLD_SIZE;
    
    // Shooting
    if ((keys[' '] || keys[32]) && player.weapon_cooldown <= 0) {
        create_projectile(player.x, player.y, player.z, player.rotation, 1);
        player.weapon_cooldown = 0.2f; // 200ms cooldown
    }
} WORLD_SIZE) player.x = WORLD_SIZE;
    if (player.x < -WORLD_SIZE) player.x = -WORLD_SIZE;
    if (player.z > WORLD_SIZE) player.z = WORLD_SIZE;
    if (player.z < -WORLD_SIZE) player.z = -WORLD_SIZE;
    
    // Shooting
    if ((keys[' '] || keys[32]) && player.weapon_cooldown <= 0) {
        create_projectile(player.x, player.y, player.z, player.rotation, 1);
        player.weapon_cooldown = 0.2f; // 200ms cooldown
    }
}

// Display function
void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    
    // Set up camera
    float cam_x = player.x + camera_distance * sin(camera_angle_y * M_PI / 180.0f) * cos(camera_angle_x * M_PI / 180.0f);
    float cam_y = player.y + camera_distance * sin(camera_angle_x * M_PI / 180.0f);
    float cam_z = player.z + camera_distance * cos(camera_angle_y * M_PI / 180.0f) * cos(camera_angle_x * M_PI / 180.0f);
    
    gluLookAt(cam_x, cam_y, cam_z, player.x, player.y, player.z, 0, 1, 0);
    
    // Enable lighting
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    
    float light_pos[] = {10.0f, 20.0f, 10.0f, 1.0f};
    float light_color[] = {1.0f, 1.0f, 0.9f, 1.0f};
    float ambient[] = {0.3f, 0.3f, 0.4f, 1.0f};
    
    glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    
    draw_skybox();
    draw_terrain();
    draw_player();
    draw_enemies();
    
    glDisable(GL_LIGHTING);
    draw_projectiles();
    draw_hud();
    
    glutSwapBuffers();
}

// Keyboard input
void keyboard(unsigned char key, int x, int y) {
    keys[key] = 1;
    if (key == 27) exit(0); // ESC to quit
}

void keyboard_up(unsigned char key, int x, int y) {
    keys[key] = 0;
}

// Mouse input for camera control
void mouse_motion(int x, int y) {
    if (mouse_x != -1) {
        camera_angle_y += (x - mouse_x) * 0.5f;
        camera_angle_x += (y - mouse_y) * 0.5f;
        
        if (camera_angle_x > 80.0f) camera_angle_x = 80.0f;
        if (camera_angle_x < -80.0f) camera_angle_x = -80.0f;
    }
    mouse_x = x;
    mouse_y = y;
}

// Timer function for animation
void timer(int value) {
    handle_movement();
    update_game();
    glutPostRedisplay();
    glutTimerFunc(16, timer, 0); // 60 FPS
}

// Reshape function
void reshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, (float)w/h, 0.1, 1000.0);
    glMatrixMode(GL_MODELVIEW);
}

// Initialize OpenGL
void init_opengl() {
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glClearColor(0.5f, 0.7f, 1.0f, 1.0f);
    
    mouse_x = mouse_y = -1;
}

int main(int argc, char** argv) {
    printf("=== Open World Combat Game ===\n");
    printf("Controls:\n");
    printf("W/S - Move Forward/Backward\n");
    printf("A/D - Turn Left/Right\n");
    printf("Space - Shoot\n");
    printf("Mouse - Control Camera\n");
    printf("ESC - Quit\n\n");
    
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Open World Combat Game");
    
    init_opengl();
    init_game();
    
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutKeyboardUpFunc(keyboard_up);
    glutPassiveMotionFunc(mouse_motion);
    glutMotionFunc(mouse_motion);
    glutTimerFunc(0, timer, 0);
    
    printf("Game started! Defend yourself against the red enemies!\n");
    
    glutMainLoop();
    return 0;
}