#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() {
// 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
) { if (key == 27) exit(0); // ESC to quit }
void keyboard_up
(unsigned char
key, int x
, int y
) {}
// 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("W/S - Move Forward/Backward\n"); printf("A/D - Turn Left/Right\n"); printf("Mouse - Control Camera\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;
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPG1hdGguaD4KI2luY2x1ZGUgPHN0cmluZy5oPgojaW5jbHVkZSA8dGltZS5oPgoKI2lmZGVmIF9XSU4zMgogICAgI2luY2x1ZGUgPHdpbmRvd3MuaD4KICAgICNpbmNsdWRlIDxHTC9nbC5oPgogICAgI2luY2x1ZGUgPEdML2dsdS5oPgogICAgI2luY2x1ZGUgPEdML2dsdXQuaD4KICAgICNpbmNsdWRlIDx3aW5pbmV0Lmg+CiAgICAjcHJhZ21hIGNvbW1lbnQobGliLCAid2luaW5ldC5saWIiKQojZWxzZQogICAgI2luY2x1ZGUgPE9wZW5HTC9nbC5oPgogICAgI2luY2x1ZGUgPE9wZW5HTC9nbHUuaD4KICAgICNpbmNsdWRlIDxHTFVUL2dsdXQuaD4KICAgICNpbmNsdWRlIDxjdXJsL2N1cmwuaD4KI2VuZGlmCgovLyBHYW1lIGNvbnN0YW50cwojZGVmaW5lIFdPUkxEX1NJWkUgNTAuMGYKI2RlZmluZSBQTEFZRVJfU1BFRUQgMC4yZgojZGVmaW5lIEVORU1ZX0NPVU5UIDUKI2RlZmluZSBNQVhfUFJPSkVDVElMRVMgMjAKI2RlZmluZSBQUk9KRUNUSUxFX1NQRUVEIDAuNWYKI2RlZmluZSBNQVhfVVNFUk5BTUUgNTAKI2RlZmluZSBNQVhfRU1BSUwgMTAwCgovLyBHYW1lIHN0YXRlcwp0eXBlZGVmIGVudW0gewogICAgR0FNRV9TVEFURV9MT0dJTiwKICAgIEdBTUVfU1RBVEVfUExBWUlORywKICAgIEdBTUVfU1RBVEVfTUVOVQp9IEdhbWVTdGF0ZTsKCi8vIFVzZXIgYXV0aGVudGljYXRpb24gc3RydWN0dXJlCnR5cGVkZWYgc3RydWN0IHsKICAgIGNoYXIgdXNlcm5hbWVbTUFYX1VTRVJOQU1FXTsKICAgIGNoYXIgZW1haWxbTUFYX0VNQUlMXTsKICAgIGNoYXIgcHJvdmlkZXJbMjBdOyAvLyAiZmFjZWJvb2siLCAiZ21haWwiLCBvciAiZ3Vlc3QiCiAgICBpbnQgdXNlcl9pZDsKICAgIGludCBpc19sb2dnZWRfaW47CiAgICBpbnQgaGlnaF9zY29yZTsKICAgIGludCB0b3RhbF9nYW1lczsKfSBVc2VyOwoKLy8gTG9naW4gYnV0dG9uIHN0cnVjdHVyZQp0eXBlZGVmIHN0cnVjdCB7CiAgICBmbG9hdCB4LCB5LCB3aWR0aCwgaGVpZ2h0OwogICAgY2hhciB0ZXh0WzUwXTsKICAgIGZsb2F0IHIsIGcsIGI7CiAgICBpbnQgcHJvdmlkZXJfdHlwZTsgLy8gMD1mYWNlYm9vaywgMT1nbWFpbCwgMj1ndWVzdAp9IExvZ2luQnV0dG9uOwoKLy8gUGxheWVyIHN0cnVjdHVyZQp0eXBlZGVmIHN0cnVjdCB7CiAgICBmbG9hdCB4LCB5LCB6OwogICAgZmxvYXQgcm90YXRpb247CiAgICBpbnQgaGVhbHRoOwogICAgaW50IHNjb3JlOwogICAgZmxvYXQgd2VhcG9uX2Nvb2xkb3duOwp9IFBsYXllcjsKCi8vIEVuZW15IHN0cnVjdHVyZQp0eXBlZGVmIHN0cnVjdCB7CiAgICBmbG9hdCB4LCB5LCB6OwogICAgZmxvYXQgcm90YXRpb247CiAgICBpbnQgaGVhbHRoOwogICAgaW50IGFjdGl2ZTsKICAgIGZsb2F0IGFpX3RpbWVyOwp9IEVuZW15OwoKLy8gUHJvamVjdGlsZSBzdHJ1Y3R1cmUKdHlwZWRlZiBzdHJ1Y3QgewogICAgZmxvYXQgeCwgeSwgejsKICAgIGZsb2F0IGR4LCBkeSwgZHo7CiAgICBpbnQgYWN0aXZlOwogICAgaW50IGZyb21fcGxheWVyOwp9IFByb2plY3RpbGU7CgovLyBHbG9iYWwgZ2FtZSBzdGF0ZQpQbGF5ZXIgcGxheWVyID0gezAuMGYsIDEuMGYsIDAuMGYsIDAuMGYsIDEwMCwgMCwgMC4wZn07CkVuZW15IGVuZW1pZXNbRU5FTVlfQ09VTlRdOwpQcm9qZWN0aWxlIHByb2plY3RpbGVzW01BWF9QUk9KRUNUSUxFU107ClVzZXIgY3VycmVudF91c2VyID0geyIiLCAiIiwgIiIsIDAsIDAsIDAsIDB9OwpHYW1lU3RhdGUgZ2FtZV9zdGF0ZSA9IEdBTUVfU1RBVEVfTE9HSU47CkxvZ2luQnV0dG9uIGxvZ2luX2J1dHRvbnNbM107CmZsb2F0IGNhbWVyYV9hbmdsZV94ID0gMzAuMGY7CmZsb2F0IGNhbWVyYV9hbmdsZV95ID0gMC4wZjsKZmxvYXQgY2FtZXJhX2Rpc3RhbmNlID0gMTUuMGY7CmludCBrZXlzWzI1Nl0gPSB7MH07CmludCBtb3VzZV94LCBtb3VzZV95OwpmbG9hdCB0aW1lX2NvdW50ZXIgPSAwLjBmOwppbnQgd2luZG93X3dpZHRoID0gODAwLCB3aW5kb3dfaGVpZ2h0ID0gNjAwOwoKLy8gSFRUUCByZXNwb25zZSBzdHJ1Y3R1cmUgZm9yIEFQSSBjYWxscwp0eXBlZGVmIHN0cnVjdCB7CiAgICBjaGFyICpkYXRhOwogICAgc2l6ZV90IHNpemU7Cn0gSFRUUFJlc3BvbnNlOwoKLy8gV3JpdGUgY2FsbGJhY2sgZm9yIEhUVFAgcmVxdWVzdHMKc2l6ZV90IHdyaXRlX2NhbGxiYWNrKHZvaWQgKmNvbnRlbnRzLCBzaXplX3Qgc2l6ZSwgc2l6ZV90IG5tZW1iLCBIVFRQUmVzcG9uc2UgKnJlc3BvbnNlKSB7CiAgICBzaXplX3QgcmVhbF9zaXplID0gc2l6ZSAqIG5tZW1iOwogICAgY2hhciAqcHRyID0gcmVhbGxvYyhyZXNwb25zZS0+ZGF0YSwgcmVzcG9uc2UtPnNpemUgKyByZWFsX3NpemUgKyAxKTsKICAgIGlmIChwdHIgPT0gTlVMTCkgewogICAgICAgIHByaW50ZigiTm90IGVub3VnaCBtZW1vcnkgKHJlYWxsb2MgcmV0dXJuZWQgTlVMTClcbiIpOwogICAgICAgIHJldHVybiAwOwogICAgfQogICAgcmVzcG9uc2UtPmRhdGEgPSBwdHI7CiAgICBtZW1jcHkoJihyZXNwb25zZS0+ZGF0YVtyZXNwb25zZS0+c2l6ZV0pLCBjb250ZW50cywgcmVhbF9zaXplKTsKICAgIHJlc3BvbnNlLT5zaXplICs9IHJlYWxfc2l6ZTsKICAgIHJlc3BvbnNlLT5kYXRhW3Jlc3BvbnNlLT5zaXplXSA9IDA7CiAgICByZXR1cm4gcmVhbF9zaXplOwp9CgovLyBJbml0aWFsaXplIGxvZ2luIHN5c3RlbQp2b2lkIGluaXRfbG9naW5fc3lzdGVtKCkgewogICAgLy8gRmFjZWJvb2sgbG9naW4gYnV0dG9uCiAgICBsb2dpbl9idXR0b25zWzBdLnggPSAyNTA7CiAgICBsb2dpbl9idXR0b25zWzBdLnkgPSAyMDA7CiAgICBsb2dpbl9idXR0b25zWzBdLndpZHRoID0gMzAwOwogICAgbG9naW5fYnV0dG9uc1swXS5oZWlnaHQgPSA1MDsKICAgIHN0cmNweShsb2dpbl9idXR0b25zWzBdLnRleHQsICJMb2dpbiB3aXRoIEZhY2Vib29rIik7CiAgICBsb2dpbl9idXR0b25zWzBdLnIgPSAwLjIzZjsgbG9naW5fYnV0dG9uc1swXS5nID0gMC4zNWY7IGxvZ2luX2J1dHRvbnNbMF0uYiA9IDAuNjBmOwogICAgbG9naW5fYnV0dG9uc1swXS5wcm92aWRlcl90eXBlID0gMDsKICAgIAogICAgLy8gR21haWwgbG9naW4gYnV0dG9uCiAgICBsb2dpbl9idXR0b25zWzFdLnggPSAyNTA7CiAgICBsb2dpbl9idXR0b25zWzFdLnkgPSAyODA7CiAgICBsb2dpbl9idXR0b25zWzFdLndpZHRoID0gMzAwOwogICAgbG9naW5fYnV0dG9uc1sxXS5oZWlnaHQgPSA1MDsKICAgIHN0cmNweShsb2dpbl9idXR0b25zWzFdLnRleHQsICJMb2dpbiB3aXRoIEdtYWlsIik7CiAgICBsb2dpbl9idXR0b25zWzFdLnIgPSAwLjg1ZjsgbG9naW5fYnV0dG9uc1sxXS5nID0gMC4yNmY7IGxvZ2luX2J1dHRvbnNbMV0uYiA9IDAuMjFmOwogICAgbG9naW5fYnV0dG9uc1sxXS5wcm92aWRlcl90eXBlID0gMTsKICAgIAogICAgLy8gR3Vlc3QgbG9naW4gYnV0dG9uCiAgICBsb2dpbl9idXR0b25zWzJdLnggPSAyNTA7CiAgICBsb2dpbl9idXR0b25zWzJdLnkgPSAzNjA7CiAgICBsb2dpbl9idXR0b25zWzJdLndpZHRoID0gMzAwOwogICAgbG9naW5fYnV0dG9uc1syXS5oZWlnaHQgPSA1MDsKICAgIHN0cmNweShsb2dpbl9idXR0b25zWzJdLnRleHQsICJQbGF5IGFzIEd1ZXN0Iik7CiAgICBsb2dpbl9idXR0b25zWzJdLnIgPSAwLjVmOyBsb2dpbl9idXR0b25zWzJdLmcgPSAwLjVmOyBsb2dpbl9idXR0b25zWzJdLmIgPSAwLjVmOwogICAgbG9naW5fYnV0dG9uc1syXS5wcm92aWRlcl90eXBlID0gMjsKfQoKLy8gU2ltdWxhdGUgT0F1dGggYXV0aGVudGljYXRpb24gKGluIHJlYWwgaW1wbGVtZW50YXRpb24sIHRoaXMgd291bGQgb3BlbiBicm93c2VyKQppbnQgYXV0aGVudGljYXRlX3dpdGhfcHJvdmlkZXIoaW50IHByb3ZpZGVyX3R5cGUpIHsKICAgIHN3aXRjaChwcm92aWRlcl90eXBlKSB7CiAgICAgICAgY2FzZSAwOiAvLyBGYWNlYm9vawogICAgICAgICAgICBwcmludGYoIk9wZW5pbmcgRmFjZWJvb2sgT0F1dGguLi4gKHNpbXVsYXRlZClcbiIpOwogICAgICAgICAgICBzdHJjcHkoY3VycmVudF91c2VyLnVzZXJuYW1lLCAiRmFjZWJvb2sgVXNlciIpOwogICAgICAgICAgICBzdHJjcHkoY3VycmVudF91c2VyLmVtYWlsLCAidXNlckBmYWNlYm9vay5jb20iKTsKICAgICAgICAgICAgc3RyY3B5KGN1cnJlbnRfdXNlci5wcm92aWRlciwgImZhY2Vib29rIik7CiAgICAgICAgICAgIGN1cnJlbnRfdXNlci51c2VyX2lkID0gMTIzNDU7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIGNhc2UgMTogLy8gR21haWwKICAgICAgICAgICAgcHJpbnRmKCJPcGVuaW5nIEdvb2dsZSBPQXV0aC4uLiAoc2ltdWxhdGVkKVxuIik7CiAgICAgICAgICAgIHN0cmNweShjdXJyZW50X3VzZXIudXNlcm5hbWUsICJHbWFpbCBVc2VyIik7CiAgICAgICAgICAgIHN0cmNweShjdXJyZW50X3VzZXIuZW1haWwsICJ1c2VyQGdtYWlsLmNvbSIpOwogICAgICAgICAgICBzdHJjcHkoY3VycmVudF91c2VyLnByb3ZpZGVyLCAiZ21haWwiKTsKICAgICAgICAgICAgY3VycmVudF91c2VyLnVzZXJfaWQgPSA2Nzg5MDsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgY2FzZSAyOiAvLyBHdWVzdAogICAgICAgICAgICBwcmludGYoIlBsYXlpbmcgYXMgZ3Vlc3QuLi5cbiIpOwogICAgICAgICAgICBzdHJjcHkoY3VycmVudF91c2VyLnVzZXJuYW1lLCAiR3Vlc3QiKTsKICAgICAgICAgICAgc3RyY3B5KGN1cnJlbnRfdXNlci5lbWFpbCwgIiIpOwogICAgICAgICAgICBzdHJjcHkoY3VycmVudF91c2VyLnByb3ZpZGVyLCAiZ3Vlc3QiKTsKICAgICAgICAgICAgY3VycmVudF91c2VyLnVzZXJfaWQgPSByYW5kKCkgJSAxMDAwMDsKICAgICAgICAgICAgYnJlYWs7CiAgICB9CiAgICAKICAgIGN1cnJlbnRfdXNlci5pc19sb2dnZWRfaW4gPSAxOwogICAgY3VycmVudF91c2VyLmhpZ2hfc2NvcmUgPSAwOwogICAgY3VycmVudF91c2VyLnRvdGFsX2dhbWVzID0gMDsKICAgIAogICAgcHJpbnRmKCJMb2dnZWQgaW4gYXM6ICVzICglcylcbiIsIGN1cnJlbnRfdXNlci51c2VybmFtZSwgY3VycmVudF91c2VyLnByb3ZpZGVyKTsKICAgIHJldHVybiAxOwp9CgovLyBTYXZlIHVzZXIgZGF0YSB0byBzZXJ2ZXIgKHNpbXVsYXRlZCkKdm9pZCBzYXZlX3VzZXJfZGF0YSgpIHsKICAgIGlmICghY3VycmVudF91c2VyLmlzX2xvZ2dlZF9pbiB8fCBzdHJjbXAoY3VycmVudF91c2VyLnByb3ZpZGVyLCAiZ3Vlc3QiKSA9PSAwKSB7CiAgICAgICAgcmV0dXJuOwogICAgfQogICAgCiAgICBwcmludGYoIlNhdmluZyB1c2VyIGRhdGEgdG8gc2VydmVyLi4uXG4iKTsKICAgIHByaW50ZigiVXNlcjogJXMsIEhpZ2ggU2NvcmU6ICVkLCBHYW1lczogJWRcbiIsIAogICAgICAgICAgIGN1cnJlbnRfdXNlci51c2VybmFtZSwgY3VycmVudF91c2VyLmhpZ2hfc2NvcmUsIGN1cnJlbnRfdXNlci50b3RhbF9nYW1lcyk7CiAgICAKICAgIC8vIEluIHJlYWwgaW1wbGVtZW50YXRpb24sIHRoaXMgd291bGQgbWFrZSBIVFRQIFBPU1QgdG8geW91ciBnYW1lIHNlcnZlcgogICAgLy8gRXhhbXBsZTogUE9TVCAvYXBpL3VzZXJzL3t1c2VyX2lkfS9zYXZlIHdpdGggc2NvcmUgZGF0YQp9CgovLyBMb2FkIHVzZXIgZGF0YSBmcm9tIHNlcnZlciAoc2ltdWxhdGVkKQp2b2lkIGxvYWRfdXNlcl9kYXRhKCkgewogICAgaWYgKCFjdXJyZW50X3VzZXIuaXNfbG9nZ2VkX2luIHx8IHN0cmNtcChjdXJyZW50X3VzZXIucHJvdmlkZXIsICJndWVzdCIpID09IDApIHsKICAgICAgICByZXR1cm47CiAgICB9CiAgICAKICAgIHByaW50ZigiTG9hZGluZyB1c2VyIGRhdGEgZnJvbSBzZXJ2ZXIuLi5cbiIpOwogICAgCiAgICAvLyBTaW11bGF0ZSBsb2FkaW5nIHNhdmVkIGRhdGEKICAgIGN1cnJlbnRfdXNlci5oaWdoX3Njb3JlID0gMTI1MDsgLy8gRXhhbXBsZSBzYXZlZCBoaWdoIHNjb3JlCiAgICBjdXJyZW50X3VzZXIudG90YWxfZ2FtZXMgPSAxNTsgIC8vIEV4YW1wbGUgZ2FtZXMgcGxheWVkCiAgICAKICAgIHByaW50ZigiTG9hZGVkOiBIaWdoIFNjb3JlOiAlZCwgR2FtZXMgUGxheWVkOiAlZFxuIiwgCiAgICAgICAgICAgY3VycmVudF91c2VyLmhpZ2hfc2NvcmUsIGN1cnJlbnRfdXNlci50b3RhbF9nYW1lcyk7Cn0KCi8vIERyYXcgdGV4dCBmdW5jdGlvbiAoc2ltcGxpZmllZCkKdm9pZCBkcmF3X3RleHQoZmxvYXQgeCwgZmxvYXQgeSwgY29uc3QgY2hhciogdGV4dCwgZmxvYXQgciwgZmxvYXQgZywgZmxvYXQgYikgewogICAgZ2xDb2xvcjNmKHIsIGcsIGIpOwogICAgZ2xSYXN0ZXJQb3MyZih4LCB5KTsKICAgIGZvciAoaW50IGkgPSAwOyB0ZXh0W2ldICE9ICdcMCc7IGkrKykgewogICAgICAgIGdsdXRCaXRtYXBDaGFyYWN0ZXIoR0xVVF9CSVRNQVBfSEVMVkVUSUNBXzE4LCB0ZXh0W2ldKTsKICAgIH0KfQoKLy8gRHJhdyBsb2dpbiBzY3JlZW4Kdm9pZCBkcmF3X2xvZ2luX3NjcmVlbigpIHsKICAgIGdsQ2xlYXIoR0xfQ09MT1JfQlVGRkVSX0JJVCB8IEdMX0RFUFRIX0JVRkZFUl9CSVQpOwogICAgCiAgICAvLyBTZXQgdXAgMkQgcmVuZGVyaW5nCiAgICBnbE1hdHJpeE1vZGUoR0xfUFJPSkVDVElPTik7CiAgICBnbFB1c2hNYXRyaXgoKTsKICAgIGdsTG9hZElkZW50aXR5KCk7CiAgICBnbE9ydGhvKDAsIHdpbmRvd193aWR0aCwgd2luZG93X2hlaWdodCwgMCwgLTEsIDEpOwogICAgZ2xNYXRyaXhNb2RlKEdMX01PREVMVklFVyk7CiAgICBnbFB1c2hNYXRyaXgoKTsKICAgIGdsTG9hZElkZW50aXR5KCk7CiAgICAKICAgIGdsRGlzYWJsZShHTF9ERVBUSF9URVNUKTsKICAgIAogICAgLy8gQmFja2dyb3VuZCBncmFkaWVudAogICAgZ2xCZWdpbihHTF9RVUFEUyk7CiAgICBnbENvbG9yM2YoMC4xZiwgMC4xZiwgMC4yZik7CiAgICBnbFZlcnRleDJmKDAsIDApOwogICAgZ2xWZXJ0ZXgyZih3aW5kb3dfd2lkdGgsIDApOwogICAgZ2xDb2xvcjNmKDAuMmYsIDAuMWYsIDAuM2YpOwogICAgZ2xWZXJ0ZXgyZih3aW5kb3dfd2lkdGgsIHdpbmRvd19oZWlnaHQpOwogICAgZ2xWZXJ0ZXgyZigwLCB3aW5kb3dfaGVpZ2h0KTsKICAgIGdsRW5kKCk7CiAgICAKICAgIC8vIEdhbWUgdGl0bGUKICAgIGRyYXdfdGV4dCgyNTAsIDEwMCwgIk9QRU4gV09STEQgQ09NQkFUIEdBTUUiLCAxLjBmLCAxLjBmLCAxLjBmKTsKICAgIGRyYXdfdGV4dCgzMDAsIDEzMCwgIkNob29zZSBMb2dpbiBNZXRob2QiLCAwLjhmLCAwLjhmLCAwLjhmKTsKICAgIAogICAgLy8gRHJhdyBsb2dpbiBidXR0b25zCiAgICBmb3IgKGludCBpID0gMDsgaSA8IDM7IGkrKykgewogICAgICAgIExvZ2luQnV0dG9uKiBidG4gPSAmbG9naW5fYnV0dG9uc1tpXTsKICAgICAgICAKICAgICAgICAvLyBCdXR0b24gYmFja2dyb3VuZAogICAgICAgIGdsQ29sb3IzZihidG4tPnIsIGJ0bi0+ZywgYnRuLT5iKTsKICAgICAgICBnbEJlZ2luKEdMX1FVQURTKTsKICAgICAgICBnbFZlcnRleDJmKGJ0bi0+eCwgYnRuLT55KTsKICAgICAgICBnbFZlcnRleDJmKGJ0bi0+eCArIGJ0bi0+d2lkdGgsIGJ0bi0+eSk7CiAgICAgICAgZ2xWZXJ0ZXgyZihidG4tPnggKyBidG4tPndpZHRoLCBidG4tPnkgKyBidG4tPmhlaWdodCk7CiAgICAgICAgZ2xWZXJ0ZXgyZihidG4tPngsIGJ0bi0+eSArIGJ0bi0+aGVpZ2h0KTsKICAgICAgICBnbEVuZCgpOwogICAgICAgIAogICAgICAgIC8vIEJ1dHRvbiBib3JkZXIKICAgICAgICBnbENvbG9yM2YoMS4wZiwgMS4wZiwgMS4wZik7CiAgICAgICAgZ2xMaW5lV2lkdGgoMi4wZik7CiAgICAgICAgZ2xCZWdpbihHTF9MSU5FX0xPT1ApOwogICAgICAgIGdsVmVydGV4MmYoYnRuLT54LCBidG4tPnkpOwogICAgICAgIGdsVmVydGV4MmYoYnRuLT54ICsgYnRuLT53aWR0aCwgYnRuLT55KTsKICAgICAgICBnbFZlcnRleDJmKGJ0bi0+eCArIGJ0bi0+d2lkdGgsIGJ0bi0+eSArIGJ0bi0+aGVpZ2h0KTsKICAgICAgICBnbFZlcnRleDJmKGJ0bi0+eCwgYnRuLT55ICsgYnRuLT5oZWlnaHQpOwogICAgICAgIGdsRW5kKCk7CiAgICAgICAgCiAgICAgICAgLy8gQnV0dG9uIHRleHQKICAgICAgICBkcmF3X3RleHQoYnRuLT54ICsgNTAsIGJ0bi0+eSArIDMwLCBidG4tPnRleHQsIDEuMGYsIDEuMGYsIDEuMGYpOwogICAgfQogICAgCiAgICAvLyBJbnN0cnVjdGlvbnMKICAgIGRyYXdfdGV4dCgyMDAsIDUwMCwgIkNsaWNrIG9uIGEgYnV0dG9uIHRvIGxvZ2luIGFuZCBzdGFydCBwbGF5aW5nISIsIDAuN2YsIDAuN2YsIDAuN2YpOwogICAgCiAgICBnbEVuYWJsZShHTF9ERVBUSF9URVNUKTsKICAgIGdsUG9wTWF0cml4KCk7CiAgICBnbE1hdHJpeE1vZGUoR0xfUFJPSkVDVElPTik7CiAgICBnbFBvcE1hdHJpeCgpOwogICAgZ2xNYXRyaXhNb2RlKEdMX01PREVMVklFVyk7Cn0Kdm9pZCBpbml0X2dhbWUoKSB7CiAgICBzcmFuZCh0aW1lKE5VTEwpKTsKICAgIAogICAgLy8gSW5pdGlhbGl6ZSBlbmVtaWVzCiAgICBmb3IgKGludCBpID0gMDsgaSA8IEVORU1ZX0NPVU5UOyBpKyspIHsKICAgICAgICBlbmVtaWVzW2ldLnggPSAocmFuZCgpICUgNDApIC0gMjAuMGY7CiAgICAgICAgZW5lbWllc1tpXS56ID0gKHJhbmQoKSAlIDQwKSAtIDIwLjBmOwogICAgICAgIGVuZW1pZXNbaV0ueSA9IDEuMGY7CiAgICAgICAgZW5lbWllc1tpXS5yb3RhdGlvbiA9IHJhbmQoKSAlIDM2MDsKICAgICAgICBlbmVtaWVzW2ldLmhlYWx0aCA9IDUwOwogICAgICAgIGVuZW1pZXNbaV0uYWN0aXZlID0gMTsKICAgICAgICBlbmVtaWVzW2ldLmFpX3RpbWVyID0gMC4wZjsKICAgIH0KICAgIAogICAgLy8gSW5pdGlhbGl6ZSBwcm9qZWN0aWxlcwogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBNQVhfUFJPSkVDVElMRVM7IGkrKykgewogICAgICAgIHByb2plY3RpbGVzW2ldLmFjdGl2ZSA9IDA7CiAgICB9Cn0KCi8vIENyZWF0ZSBhIHByb2plY3RpbGUKdm9pZCBjcmVhdGVfcHJvamVjdGlsZShmbG9hdCB4LCBmbG9hdCB5LCBmbG9hdCB6LCBmbG9hdCBhbmdsZSwgaW50IGZyb21fcGxheWVyKSB7CiAgICBmb3IgKGludCBpID0gMDsgaSA8IE1BWF9QUk9KRUNUSUxFUzsgaSsrKSB7CiAgICAgICAgaWYgKCFwcm9qZWN0aWxlc1tpXS5hY3RpdmUpIHsKICAgICAgICAgICAgcHJvamVjdGlsZXNbaV0ueCA9IHg7CiAgICAgICAgICAgIHByb2plY3RpbGVzW2ldLnkgPSB5OwogICAgICAgICAgICBwcm9qZWN0aWxlc1tpXS56ID0gejsKICAgICAgICAgICAgcHJvamVjdGlsZXNbaV0uZHggPSBzaW4oYW5nbGUgKiBNX1BJIC8gMTgwLjBmKSAqIFBST0pFQ1RJTEVfU1BFRUQ7CiAgICAgICAgICAgIHByb2plY3RpbGVzW2ldLmR6ID0gLWNvcyhhbmdsZSAqIE1fUEkgLyAxODAuMGYpICogUFJPSkVDVElMRV9TUEVFRDsKICAgICAgICAgICAgcHJvamVjdGlsZXNbaV0uZHkgPSAwLjBmOwogICAgICAgICAgICBwcm9qZWN0aWxlc1tpXS5hY3RpdmUgPSAxOwogICAgICAgICAgICBwcm9qZWN0aWxlc1tpXS5mcm9tX3BsYXllciA9IGZyb21fcGxheWVyOwogICAgICAgICAgICBicmVhazsKICAgICAgICB9CiAgICB9Cn0KCi8vIERyYXcgYSBjdWJlIHdpdGggZ3JhZGllbnRzCnZvaWQgZHJhd19ncmFkaWVudF9jdWJlKGZsb2F0IHNpemUsIGZsb2F0IHIxLCBmbG9hdCBnMSwgZmxvYXQgYjEsIGZsb2F0IHIyLCBmbG9hdCBnMiwgZmxvYXQgYjIpIHsKICAgIGdsQmVnaW4oR0xfUVVBRFMpOwogICAgCiAgICAvLyBGcm9udCBmYWNlIChncmFkaWVudCkKICAgIGdsQ29sb3IzZihyMSwgZzEsIGIxKTsgZ2xWZXJ0ZXgzZigtc2l6ZSwgLXNpemUsIHNpemUpOwogICAgZ2xDb2xvcjNmKHIxLCBnMSwgYjEpOyBnbFZlcnRleDNmKHNpemUsIC1zaXplLCBzaXplKTsKICAgIGdsQ29sb3IzZihyMiwgZzIsIGIyKTsgZ2xWZXJ0ZXgzZihzaXplLCBzaXplLCBzaXplKTsKICAgIGdsQ29sb3IzZihyMiwgZzIsIGIyKTsgZ2xWZXJ0ZXgzZigtc2l6ZSwgc2l6ZSwgc2l6ZSk7CiAgICAKICAgIC8vIEJhY2sgZmFjZQogICAgZ2xDb2xvcjNmKHIxKjAuN2YsIGcxKjAuN2YsIGIxKjAuN2YpOyBnbFZlcnRleDNmKC1zaXplLCAtc2l6ZSwgLXNpemUpOwogICAgZ2xDb2xvcjNmKHIxKjAuN2YsIGcxKjAuN2YsIGIxKjAuN2YpOyBnbFZlcnRleDNmKC1zaXplLCBzaXplLCAtc2l6ZSk7CiAgICBnbENvbG9yM2YocjIqMC43ZiwgZzIqMC43ZiwgYjIqMC43Zik7IGdsVmVydGV4M2Yoc2l6ZSwgc2l6ZSwgLXNpemUpOwogICAgZ2xDb2xvcjNmKHIyKjAuN2YsIGcyKjAuN2YsIGIyKjAuN2YpOyBnbFZlcnRleDNmKHNpemUsIC1zaXplLCAtc2l6ZSk7CiAgICAKICAgIC8vIFRvcCBmYWNlCiAgICBnbENvbG9yM2YocjIsIGcyLCBiMik7IGdsVmVydGV4M2YoLXNpemUsIHNpemUsIC1zaXplKTsKICAgIGdsQ29sb3IzZihyMiwgZzIsIGIyKTsgZ2xWZXJ0ZXgzZigtc2l6ZSwgc2l6ZSwgc2l6ZSk7CiAgICBnbENvbG9yM2YocjIsIGcyLCBiMik7IGdsVmVydGV4M2Yoc2l6ZSwgc2l6ZSwgc2l6ZSk7CiAgICBnbENvbG9yM2YocjIsIGcyLCBiMik7IGdsVmVydGV4M2Yoc2l6ZSwgc2l6ZSwgLXNpemUpOwogICAgCiAgICAvLyBCb3R0b20gZmFjZQogICAgZ2xDb2xvcjNmKHIxKjAuNWYsIGcxKjAuNWYsIGIxKjAuNWYpOyBnbFZlcnRleDNmKC1zaXplLCAtc2l6ZSwgLXNpemUpOwogICAgZ2xDb2xvcjNmKHIxKjAuNWYsIGcxKjAuNWYsIGIxKjAuNWYpOyBnbFZlcnRleDNmKHNpemUsIC1zaXplLCAtc2l6ZSk7CiAgICBnbENvbG9yM2YocjEqMC41ZiwgZzEqMC41ZiwgYjEqMC41Zik7IGdsVmVydGV4M2Yoc2l6ZSwgLXNpemUsIHNpemUpOwogICAgZ2xDb2xvcjNmKHIxKjAuNWYsIGcxKjAuNWYsIGIxKjAuNWYpOyBnbFZlcnRleDNmKC1zaXplLCAtc2l6ZSwgc2l6ZSk7CiAgICAKICAgIC8vIFJpZ2h0IGZhY2UKICAgIGdsQ29sb3IzZihyMSowLjhmLCBnMSowLjhmLCBiMSowLjhmKTsgZ2xWZXJ0ZXgzZihzaXplLCAtc2l6ZSwgLXNpemUpOwogICAgZ2xDb2xvcjNmKHIyKjAuOGYsIGcyKjAuOGYsIGIyKjAuOGYpOyBnbFZlcnRleDNmKHNpemUsIHNpemUsIC1zaXplKTsKICAgIGdsQ29sb3IzZihyMiowLjhmLCBnMiowLjhmLCBiMiowLjhmKTsgZ2xWZXJ0ZXgzZihzaXplLCBzaXplLCBzaXplKTsKICAgIGdsQ29sb3IzZihyMSowLjhmLCBnMSowLjhmLCBiMSowLjhmKTsgZ2xWZXJ0ZXgzZihzaXplLCAtc2l6ZSwgc2l6ZSk7CiAgICAKICAgIC8vIExlZnQgZmFjZQogICAgZ2xDb2xvcjNmKHIxKjAuOGYsIGcxKjAuOGYsIGIxKjAuOGYpOyBnbFZlcnRleDNmKC1zaXplLCAtc2l6ZSwgLXNpemUpOwogICAgZ2xDb2xvcjNmKHIxKjAuOGYsIGcxKjAuOGYsIGIxKjAuOGYpOyBnbFZlcnRleDNmKC1zaXplLCAtc2l6ZSwgc2l6ZSk7CiAgICBnbENvbG9yM2YocjIqMC44ZiwgZzIqMC44ZiwgYjIqMC44Zik7IGdsVmVydGV4M2YoLXNpemUsIHNpemUsIHNpemUpOwogICAgZ2xDb2xvcjNmKHIyKjAuOGYsIGcyKjAuOGYsIGIyKjAuOGYpOyBnbFZlcnRleDNmKC1zaXplLCBzaXplLCAtc2l6ZSk7CiAgICAKICAgIGdsRW5kKCk7Cn0KCi8vIERyYXcgdGhlIHRlcnJhaW4Kdm9pZCBkcmF3X3RlcnJhaW4oKSB7CiAgICBnbENvbG9yM2YoMC4yZiwgMC42ZiwgMC4yZik7CiAgICBnbEJlZ2luKEdMX1FVQURTKTsKICAgIGZvciAoaW50IHggPSAtV09STERfU0laRTsgeCA8IFdPUkxEX1NJWkU7IHggKz0gMikgewogICAgICAgIGZvciAoaW50IHogPSAtV09STERfU0laRTsgeiA8IFdPUkxEX1NJWkU7IHogKz0gMikgewogICAgICAgICAgICBmbG9hdCBoZWlnaHQxID0gc2luKHggKiAwLjFmKSAqIGNvcyh6ICogMC4xZikgKiAwLjVmOwogICAgICAgICAgICBmbG9hdCBoZWlnaHQyID0gc2luKCh4KzIpICogMC4xZikgKiBjb3MoeiAqIDAuMWYpICogMC41ZjsKICAgICAgICAgICAgZmxvYXQgaGVpZ2h0MyA9IHNpbigoeCsyKSAqIDAuMWYpICogY29zKCh6KzIpICogMC4xZikgKiAwLjVmOwogICAgICAgICAgICBmbG9hdCBoZWlnaHQ0ID0gc2luKHggKiAwLjFmKSAqIGNvcygoeisyKSAqIDAuMWYpICogMC41ZjsKICAgICAgICAgICAgCiAgICAgICAgICAgIGdsQ29sb3IzZigwLjJmICsgaGVpZ2h0MSowLjJmLCAwLjZmICsgaGVpZ2h0MSowLjFmLCAwLjJmKTsKICAgICAgICAgICAgZ2xWZXJ0ZXgzZih4LCBoZWlnaHQxLCB6KTsKICAgICAgICAgICAgZ2xDb2xvcjNmKDAuMmYgKyBoZWlnaHQyKjAuMmYsIDAuNmYgKyBoZWlnaHQyKjAuMWYsIDAuMmYpOwogICAgICAgICAgICBnbFZlcnRleDNmKHgrMiwgaGVpZ2h0Miwgeik7CiAgICAgICAgICAgIGdsQ29sb3IzZigwLjJmICsgaGVpZ2h0MyowLjJmLCAwLjZmICsgaGVpZ2h0MyowLjFmLCAwLjJmKTsKICAgICAgICAgICAgZ2xWZXJ0ZXgzZih4KzIsIGhlaWdodDMsIHorMik7CiAgICAgICAgICAgIGdsQ29sb3IzZigwLjJmICsgaGVpZ2h0NCowLjJmLCAwLjZmICsgaGVpZ2h0NCowLjFmLCAwLjJmKTsKICAgICAgICAgICAgZ2xWZXJ0ZXgzZih4LCBoZWlnaHQ0LCB6KzIpOwogICAgICAgIH0KICAgIH0KICAgIGdsRW5kKCk7Cn0KCi8vIERyYXcgcGxheWVyCnZvaWQgZHJhd19wbGF5ZXIoKSB7CiAgICBnbFB1c2hNYXRyaXgoKTsKICAgIGdsVHJhbnNsYXRlZihwbGF5ZXIueCwgcGxheWVyLnksIHBsYXllci56KTsKICAgIGdsUm90YXRlZihwbGF5ZXIucm90YXRpb24sIDAsIDEsIDApOwogICAgCiAgICAvLyBQbGF5ZXIgYm9keSAoYmx1ZSBncmFkaWVudCkKICAgIGRyYXdfZ3JhZGllbnRfY3ViZSgwLjVmLCAwLjNmLCAwLjNmLCAxLjBmLCAwLjZmLCAwLjZmLCAxLjBmKTsKICAgIAogICAgLy8gUGxheWVyIHdlYXBvbgogICAgZ2xQdXNoTWF0cml4KCk7CiAgICBnbFRyYW5zbGF0ZWYoMC43ZiwgMC4yZiwgMC4wZik7CiAgICBnbFNjYWxlZigwLjhmLCAwLjFmLCAwLjFmKTsKICAgIGRyYXdfZ3JhZGllbnRfY3ViZSgwLjNmLCAwLjhmLCAwLjhmLCAwLjhmLCAwLjVmLCAwLjVmLCAwLjVmKTsKICAgIGdsUG9wTWF0cml4KCk7CiAgICAKICAgIGdsUG9wTWF0cml4KCk7Cn0KCi8vIERyYXcgZW5lbWllcwp2b2lkIGRyYXdfZW5lbWllcygpIHsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgRU5FTVlfQ09VTlQ7IGkrKykgewogICAgICAgIGlmIChlbmVtaWVzW2ldLmFjdGl2ZSkgewogICAgICAgICAgICBnbFB1c2hNYXRyaXgoKTsKICAgICAgICAgICAgZ2xUcmFuc2xhdGVmKGVuZW1pZXNbaV0ueCwgZW5lbWllc1tpXS55LCBlbmVtaWVzW2ldLnopOwogICAgICAgICAgICBnbFJvdGF0ZWYoZW5lbWllc1tpXS5yb3RhdGlvbiwgMCwgMSwgMCk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBFbmVteSBib2R5IChyZWQgZ3JhZGllbnQpCiAgICAgICAgICAgIGRyYXdfZ3JhZGllbnRfY3ViZSgwLjRmLCAxLjBmLCAwLjJmLCAwLjJmLCAwLjZmLCAwLjFmLCAwLjFmKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIGdsUG9wTWF0cml4KCk7CiAgICAgICAgfQogICAgfQp9CgovLyBEcmF3IHByb2plY3RpbGVzCnZvaWQgZHJhd19wcm9qZWN0aWxlcygpIHsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgTUFYX1BST0pFQ1RJTEVTOyBpKyspIHsKICAgICAgICBpZiAocHJvamVjdGlsZXNbaV0uYWN0aXZlKSB7CiAgICAgICAgICAgIGdsUHVzaE1hdHJpeCgpOwogICAgICAgICAgICBnbFRyYW5zbGF0ZWYocHJvamVjdGlsZXNbaV0ueCwgcHJvamVjdGlsZXNbaV0ueSwgcHJvamVjdGlsZXNbaV0ueik7CiAgICAgICAgICAgIAogICAgICAgICAgICBpZiAocHJvamVjdGlsZXNbaV0uZnJvbV9wbGF5ZXIpIHsKICAgICAgICAgICAgICAgIGdsQ29sb3IzZigwLjBmLCAxLjBmLCAxLjBmKTsgLy8gQ3lhbiBmb3IgcGxheWVyIHByb2plY3RpbGVzCiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBnbENvbG9yM2YoMS4wZiwgMC41ZiwgMC4wZik7IC8vIE9yYW5nZSBmb3IgZW5lbXkgcHJvamVjdGlsZXMKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgZ2x1dFNvbGlkU3BoZXJlKDAuMWYsIDgsIDgpOwogICAgICAgICAgICBnbFBvcE1hdHJpeCgpOwogICAgICAgIH0KICAgIH0KfQoKLy8gRHJhdyBza3lib3gKdm9pZCBkcmF3X3NreWJveCgpIHsKICAgIGdsRGlzYWJsZShHTF9ERVBUSF9URVNUKTsKICAgIGdsUHVzaE1hdHJpeCgpOwogICAgZ2xMb2FkSWRlbnRpdHkoKTsKICAgIAogICAgLy8gQ3JlYXRlIGEgZ3JhZGllbnQgc2t5CiAgICBnbEJlZ2luKEdMX1FVQURTKTsKICAgIC8vIFNreSBncmFkaWVudCBmcm9tIGhvcml6b24gdG8gemVuaXRoCiAgICBnbENvbG9yM2YoMC42ZiwgMC44ZiwgMS4wZik7IC8vIExpZ2h0IGJsdWUgYXQgaG9yaXpvbgogICAgZ2xWZXJ0ZXgzZigtNTAsIC01MCwgLTUwKTsKICAgIGdsVmVydGV4M2YoNTAsIC01MCwgLTUwKTsKICAgIGdsQ29sb3IzZigwLjJmLCAwLjRmLCAwLjhmKTsgLy8gRGFya2VyIGJsdWUgYXQgdG9wCiAgICBnbFZlcnRleDNmKDUwLCA1MCwgLTUwKTsKICAgIGdsVmVydGV4M2YoLTUwLCA1MCwgLTUwKTsKICAgIGdsRW5kKCk7CiAgICAKICAgIGdsUG9wTWF0cml4KCk7CiAgICBnbEVuYWJsZShHTF9ERVBUSF9URVNUKTsKfQoKLy8gRHJhdyBIVUQgd2l0aCB1c2VyIGluZm8Kdm9pZCBkcmF3X2h1ZCgpIHsKICAgIGdsTWF0cml4TW9kZShHTF9QUk9KRUNUSU9OKTsKICAgIGdsUHVzaE1hdHJpeCgpOwogICAgZ2xMb2FkSWRlbnRpdHkoKTsKICAgIGdsT3J0aG8oMCwgd2luZG93X3dpZHRoLCB3aW5kb3dfaGVpZ2h0LCAwLCAtMSwgMSk7CiAgICBnbE1hdHJpeE1vZGUoR0xfTU9ERUxWSUVXKTsKICAgIGdsUHVzaE1hdHJpeCgpOwogICAgZ2xMb2FkSWRlbnRpdHkoKTsKICAgIAogICAgZ2xEaXNhYmxlKEdMX0RFUFRIX1RFU1QpOwogICAgCiAgICAvLyBIZWFsdGggYmFyIGJhY2tncm91bmQKICAgIGdsQ29sb3IzZigwLjJmLCAwLjJmLCAwLjJmKTsKICAgIGdsQmVnaW4oR0xfUVVBRFMpOwogICAgZ2xWZXJ0ZXgyZigxMCwgMTApOwogICAgZ2xWZXJ0ZXgyZigyMTAsIDEwKTsKICAgIGdsVmVydGV4MmYoMjEwLCAzMCk7CiAgICBnbFZlcnRleDJmKDEwLCAzMCk7CiAgICBnbEVuZCgpOwogICAgCiAgICAvLyBIZWFsdGggYmFyCiAgICBnbENvbG9yM2YoMS4wZiwgMC4wZiwgMC4wZik7CiAgICBnbEJlZ2luKEdMX1FVQURTKTsKICAgIGdsVmVydGV4MmYoMTAsIDEwKTsKICAgIGdsVmVydGV4MmYoMTAgKyAocGxheWVyLmhlYWx0aCAqIDIpLCAxMCk7CiAgICBnbFZlcnRleDJmKDEwICsgKHBsYXllci5oZWFsdGggKiAyKSwgMzApOwogICAgZ2xWZXJ0ZXgyZigxMCwgMzApOwogICAgZ2xFbmQoKTsKICAgIAogICAgLy8gVXNlciBpbmZvIHBhbmVsCiAgICBnbENvbG9yM2YoMC4wZiwgMC4wZiwgMC4wZik7CiAgICBnbEJlZ2luKEdMX1FVQURTKTsKICAgIGdsVmVydGV4MmYod2luZG93X3dpZHRoIC0gMjUwLCAxMCk7CiAgICBnbFZlcnRleDJmKHdpbmRvd193aWR0aCAtIDEwLCAxMCk7CiAgICBnbFZlcnRleDJmKHdpbmRvd193aWR0aCAtIDEwLCAxMjApOwogICAgZ2xWZXJ0ZXgyZih3aW5kb3dfd2lkdGggLSAyNTAsIDEyMCk7CiAgICBnbEVuZCgpOwogICAgCiAgICAvLyBVc2VyIGluZm8gdGV4dAogICAgY2hhciBzY29yZV90ZXh0WzUwXSwgaGlnaF9zY29yZV90ZXh0WzUwXSwgdXNlcl90ZXh0WzEwMF07CiAgICBzcHJpbnRmKHNjb3JlX3RleHQsICJTY29yZTogJWQiLCBwbGF5ZXIuc2NvcmUpOwogICAgc3ByaW50ZihoaWdoX3Njb3JlX3RleHQsICJIaWdoIFNjb3JlOiAlZCIsIGN1cnJlbnRfdXNlci5oaWdoX3Njb3JlKTsKICAgIHNwcmludGYodXNlcl90ZXh0LCAiUGxheWVyOiAlcyIsIGN1cnJlbnRfdXNlci51c2VybmFtZSk7CiAgICAKICAgIGRyYXdfdGV4dCh3aW5kb3dfd2lkdGggLSAyNDAsIDMwLCB1c2VyX3RleHQsIDEuMGYsIDEuMGYsIDEuMGYpOwogICAgZHJhd190ZXh0KHdpbmRvd193aWR0aCAtIDI0MCwgNTAsIHNjb3JlX3RleHQsIDAuOGYsIDEuMGYsIDAuOGYpOwogICAgZHJhd190ZXh0KHdpbmRvd193aWR0aCAtIDI0MCwgNzAsIGhpZ2hfc2NvcmVfdGV4dCwgMS4wZiwgMC44ZiwgMC4yZik7CiAgICAKICAgIGlmIChjdXJyZW50X3VzZXIuaXNfbG9nZ2VkX2luICYmIHN0cmNtcChjdXJyZW50X3VzZXIucHJvdmlkZXIsICJndWVzdCIpICE9IDApIHsKICAgICAgICBkcmF3X3RleHQod2luZG93X3dpZHRoIC0gMjQwLCA5MCwgIkRhdGEgd2lsbCBiZSBzYXZlZCIsIDAuNmYsIDAuOGYsIDEuMGYpOwogICAgfQogICAgCiAgICAvLyBDb250cm9scyByZW1pbmRlcgogICAgZHJhd190ZXh0KDEwLCB3aW5kb3dfaGVpZ2h0IC0gNjAsICJXQVNEOiBNb3ZlIHwgU3BhY2U6IFNob290IHwgTW91c2U6IENhbWVyYSIsIDAuN2YsIDAuN2YsIDAuN2YpOwogICAgZHJhd190ZXh0KDEwLCB3aW5kb3dfaGVpZ2h0IC0gNDAsICJFU0M6IEJhY2sgdG8gTG9naW4iLCAwLjdmLCAwLjdmLCAwLjdmKTsKICAgIAogICAgZ2xFbmFibGUoR0xfREVQVEhfVEVTVCk7CiAgICAKICAgIGdsUG9wTWF0cml4KCk7CiAgICBnbE1hdHJpeE1vZGUoR0xfUFJPSkVDVElPTik7CiAgICBnbFBvcE1hdHJpeCgpOwogICAgZ2xNYXRyaXhNb2RlKEdMX01PREVMVklFVyk7Cn0KCi8vIFVwZGF0ZSBnYW1lIGxvZ2ljCnZvaWQgdXBkYXRlX2dhbWUoKSB7CiAgICBpZiAoZ2FtZV9zdGF0ZSAhPSBHQU1FX1NUQVRFX1BMQVlJTkcpIHJldHVybjsKICAgIAogICAgdGltZV9jb3VudGVyICs9IDAuMDE2ZjsgLy8gQXNzdW1lIDYwIEZQUwogICAgCiAgICAvLyBVcGRhdGUgd2VhcG9uIGNvb2xkb3duCiAgICBpZiAocGxheWVyLndlYXBvbl9jb29sZG93biA+IDApIHsKICAgICAgICBwbGF5ZXIud2VhcG9uX2Nvb2xkb3duIC09IDAuMDE2ZjsKICAgIH0KICAgIAogICAgLy8gVXBkYXRlIHByb2plY3RpbGVzCiAgICBmb3IgKGludCBpID0gMDsgaSA8IE1BWF9QUk9KRUNUSUxFUzsgaSsrKSB7CiAgICAgICAgaWYgKHByb2plY3RpbGVzW2ldLmFjdGl2ZSkgewogICAgICAgICAgICBwcm9qZWN0aWxlc1tpXS54ICs9IHByb2plY3RpbGVzW2ldLmR4OwogICAgICAgICAgICBwcm9qZWN0aWxlc1tpXS55ICs9IHByb2plY3RpbGVzW2ldLmR5OwogICAgICAgICAgICBwcm9qZWN0aWxlc1tpXS56ICs9IHByb2plY3RpbGVzW2ldLmR6OwogICAgICAgICAgICAKICAgICAgICAgICAgLy8gUmVtb3ZlIHByb2plY3RpbGVzIHRoYXQgYXJlIG91dCBvZiBib3VuZHMKICAgICAgICAgICAgaWYgKGZhYnMocHJvamVjdGlsZXNbaV0ueCkgPiBXT1JMRF9TSVpFIHx8IGZhYnMocHJvamVjdGlsZXNbaV0ueikgPiBXT1JMRF9TSVpFKSB7CiAgICAgICAgICAgICAgICBwcm9qZWN0aWxlc1tpXS5hY3RpdmUgPSAwOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBDaGVjayBjb2xsaXNpb24gd2l0aCBlbmVtaWVzIChpZiBmcm9tIHBsYXllcikKICAgICAgICAgICAgaWYgKHByb2plY3RpbGVzW2ldLmZyb21fcGxheWVyKSB7CiAgICAgICAgICAgICAgICBmb3IgKGludCBqID0gMDsgaiA8IEVORU1ZX0NPVU5UOyBqKyspIHsKICAgICAgICAgICAgICAgICAgICBpZiAoZW5lbWllc1tqXS5hY3RpdmUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgZmxvYXQgZHggPSBwcm9qZWN0aWxlc1tpXS54IC0gZW5lbWllc1tqXS54OwogICAgICAgICAgICAgICAgICAgICAgICBmbG9hdCBkeiA9IHByb2plY3RpbGVzW2ldLnogLSBlbmVtaWVzW2pdLno7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzcXJ0KGR4KmR4ICsgZHoqZHopIDwgMS4wZikgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5lbWllc1tqXS5oZWFsdGggLT0gMjU7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9qZWN0aWxlc1tpXS5hY3RpdmUgPSAwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxheWVyLnNjb3JlICs9IDEwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVuZW1pZXNbal0uaGVhbHRoIDw9IDApIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmVtaWVzW2pdLmFjdGl2ZSA9IDA7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxheWVyLnNjb3JlICs9IDUwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gQ2hlY2sgY29sbGlzaW9uIHdpdGggcGxheWVyIChpZiBmcm9tIGVuZW15KQogICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgIGZsb2F0IGR4ID0gcHJvamVjdGlsZXNbaV0ueCAtIHBsYXllci54OwogICAgICAgICAgICAgICAgZmxvYXQgZHogPSBwcm9qZWN0aWxlc1tpXS56IC0gcGxheWVyLno7CiAgICAgICAgICAgICAgICBpZiAoc3FydChkeCpkeCArIGR6KmR6KSA8IDEuMGYpIHsKICAgICAgICAgICAgICAgICAgICBwbGF5ZXIuaGVhbHRoIC09IDEwOwogICAgICAgICAgICAgICAgICAgIHByb2plY3RpbGVzW2ldLmFjdGl2ZSA9IDA7CiAgICAgICAgICAgICAgICAgICAgaWYgKHBsYXllci5oZWFsdGggPD0gMCkgewogICAgICAgICAgICAgICAgICAgICAgICAvLyBHYW1lIG92ZXIgLSBzYXZlIHNjb3JlIGlmIGJldHRlciB0aGFuIGhpZ2ggc2NvcmUKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBsYXllci5zY29yZSA+IGN1cnJlbnRfdXNlci5oaWdoX3Njb3JlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50X3VzZXIuaGlnaF9zY29yZSA9IHBsYXllci5zY29yZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW50ZigiTmV3IEhpZ2ggU2NvcmU6ICVkIVxuIiwgY3VycmVudF91c2VyLmhpZ2hfc2NvcmUpOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRfdXNlci50b3RhbF9nYW1lcysrOwogICAgICAgICAgICAgICAgICAgICAgICBzYXZlX3VzZXJfZGF0YSgpOwogICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgcHJpbnRmKCJHYW1lIE92ZXIhIEZpbmFsIFNjb3JlOiAlZFxuIiwgcGxheWVyLnNjb3JlKTsKICAgICAgICAgICAgICAgICAgICAgICAgcGxheWVyLmhlYWx0aCA9IDEwMDsKICAgICAgICAgICAgICAgICAgICAgICAgcGxheWVyLnNjb3JlID0gMDsKICAgICAgICAgICAgICAgICAgICAgICAgaW5pdF9nYW1lKCk7IC8vIFJlc3RhcnQKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CiAgICAKICAgIC8vIFVwZGF0ZSBlbmVtaWVzIEFJCiAgICBmb3IgKGludCBpID0gMDsgaSA8IEVORU1ZX0NPVU5UOyBpKyspIHsKICAgICAgICBpZiAoZW5lbWllc1tpXS5hY3RpdmUpIHsKICAgICAgICAgICAgZW5lbWllc1tpXS5haV90aW1lciArPSAwLjAxNmY7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBNb3ZlIHRvd2FyZHMgcGxheWVyCiAgICAgICAgICAgIGZsb2F0IGR4ID0gcGxheWVyLnggLSBlbmVtaWVzW2ldLng7CiAgICAgICAgICAgIGZsb2F0IGR6ID0gcGxheWVyLnogLSBlbmVtaWVzW2ldLno7CiAgICAgICAgICAgIGZsb2F0IGRpc3RhbmNlID0gc3FydChkeCpkeCArIGR6KmR6KTsKICAgICAgICAgICAgCiAgICAgICAgICAgIGlmIChkaXN0YW5jZSA+IDIuMGYpIHsKICAgICAgICAgICAgICAgIGVuZW1pZXNbaV0ueCArPSAoZHggLyBkaXN0YW5jZSkgKiAwLjA1ZjsKICAgICAgICAgICAgICAgIGVuZW1pZXNbaV0ueiArPSAoZHogLyBkaXN0YW5jZSkgKiAwLjA1ZjsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgLy8gUm90YXRlIHRvIGZhY2UgcGxheWVyCiAgICAgICAgICAgIGVuZW1pZXNbaV0ucm90YXRpb24gPSBhdGFuMihkeCwgLWR6KSAqIDE4MC4wZiAvIE1fUEk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBTaG9vdCBhdCBwbGF5ZXIgb2NjYXNpb25hbGx5CiAgICAgICAgICAgIGlmIChlbmVtaWVzW2ldLmFpX3RpbWVyID4gMi4wZiAmJiBkaXN0YW5jZSA8IDE1LjBmKSB7CiAgICAgICAgICAgICAgICBjcmVhdGVfcHJvamVjdGlsZShlbmVtaWVzW2ldLngsIGVuZW1pZXNbaV0ueSwgZW5lbWllc1tpXS56LCBlbmVtaWVzW2ldLnJvdGF0aW9uLCAwKTsKICAgICAgICAgICAgICAgIGVuZW1pZXNbaV0uYWlfdGltZXIgPSAwLjBmOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQogICAgCiAgICAvLyBSZXNwYXduIGVuZW1pZXMgaWYgYWxsIGFyZSBkZWZlYXRlZAogICAgaW50IGFjdGl2ZV9lbmVtaWVzID0gMDsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgRU5FTVlfQ09VTlQ7IGkrKykgewogICAgICAgIGlmIChlbmVtaWVzW2ldLmFjdGl2ZSkgYWN0aXZlX2VuZW1pZXMrKzsKICAgIH0KICAgIGlmIChhY3RpdmVfZW5lbWllcyA9PSAwKSB7CiAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBFTkVNWV9DT1VOVDsgaSsrKSB7CiAgICAgICAgICAgIGVuZW1pZXNbaV0ueCA9IChyYW5kKCkgJSA0MCkgLSAyMC4wZjsKICAgICAgICAgICAgZW5lbWllc1tpXS56ID0gKHJhbmQoKSAlIDQwKSAtIDIwLjBmOwogICAgICAgICAgICBlbmVtaWVzW2ldLmhlYWx0aCA9IDUwICsgKHBsYXllci5zY29yZSAvIDEwMCkgKiAxMDsgLy8gSW5jcmVhc2UgZGlmZmljdWx0eQogICAgICAgICAgICBlbmVtaWVzW2ldLmFjdGl2ZSA9IDE7CiAgICAgICAgfQogICAgICAgIHBsYXllci5zY29yZSArPSAxMDA7CiAgICB9Cn0KCi8vIEhhbmRsZSBtb3ZlbWVudAp2b2lkIGhhbmRsZV9tb3ZlbWVudCgpIHsKICAgIGlmIChnYW1lX3N0YXRlICE9IEdBTUVfU1RBVEVfUExBWUlORykgcmV0dXJuOwogICAgCiAgICBmbG9hdCBtb3ZlX3NwZWVkID0gUExBWUVSX1NQRUVEOwogICAgCiAgICBpZiAoa2V5c1sndyddIHx8IGtleXNbJ1cnXSkgewogICAgICAgIHBsYXllci54ICs9IHNpbihwbGF5ZXIucm90YXRpb24gKiBNX1BJIC8gMTgwLjBmKSAqIG1vdmVfc3BlZWQ7CiAgICAgICAgcGxheWVyLnogLT0gY29zKHBsYXllci5yb3RhdGlvbiAqIE1fUEkgLyAxODAuMGYpICogbW92ZV9zcGVlZDsKICAgIH0KICAgIGlmIChrZXlzWydzJ10gfHwga2V5c1snUyddKSB7CiAgICAgICAgcGxheWVyLnggLT0gc2luKHBsYXllci5yb3RhdGlvbiAqIE1fUEkgLyAxODAuMGYpICogbW92ZV9zcGVlZDsKICAgICAgICBwbGF5ZXIueiArPSBjb3MocGxheWVyLnJvdGF0aW9uICogTV9QSSAvIDE4MC4wZikgKiBtb3ZlX3NwZWVkOwogICAgfQogICAgaWYgKGtleXNbJ2EnXSB8fCBrZXlzWydBJ10pIHsKICAgICAgICBwbGF5ZXIucm90YXRpb24gLT0gMy4wZjsKICAgIH0KICAgIGlmIChrZXlzWydkJ10gfHwga2V5c1snRCddKSB7CiAgICAgICAgcGxheWVyLnJvdGF0aW9uICs9IDMuMGY7CiAgICB9CiAgICAKICAgIC8vIEtlZXAgcGxheWVyIGluIGJvdW5kcwogICAgaWYgKHBsYXllci54ID4gV09STERfU0laRSkgcGxheWVyLnggPSBXT1JMRF9TSVpFOwogICAgaWYgKHBsYXllci54IDwgLVdPUkxEX1NJWkUpIHBsYXllci54ID0gLVdPUkxEX1NJWkU7CiAgICBpZiAocGxheWVyLnogPiBXT1JMRF9TSVpFKSBwbGF5ZXIueiA9IFdPUkxEX1NJWkU7CiAgICBpZiAocGxheWVyLnogPCAtV09STERfU0laRSkgcGxheWVyLnogPSAtV09STERfU0laRTsKICAgIAogICAgLy8gU2hvb3RpbmcKICAgIGlmICgoa2V5c1snICddIHx8IGtleXNbMzJdKSAmJiBwbGF5ZXIud2VhcG9uX2Nvb2xkb3duIDw9IDApIHsKICAgICAgICBjcmVhdGVfcHJvamVjdGlsZShwbGF5ZXIueCwgcGxheWVyLnksIHBsYXllci56LCBwbGF5ZXIucm90YXRpb24sIDEpOwogICAgICAgIHBsYXllci53ZWFwb25fY29vbGRvd24gPSAwLjJmOyAvLyAyMDBtcyBjb29sZG93bgogICAgfQp9IFdPUkxEX1NJWkUpIHBsYXllci54ID0gV09STERfU0laRTsKICAgIGlmIChwbGF5ZXIueCA8IC1XT1JMRF9TSVpFKSBwbGF5ZXIueCA9IC1XT1JMRF9TSVpFOwogICAgaWYgKHBsYXllci56ID4gV09STERfU0laRSkgcGxheWVyLnogPSBXT1JMRF9TSVpFOwogICAgaWYgKHBsYXllci56IDwgLVdPUkxEX1NJWkUpIHBsYXllci56ID0gLVdPUkxEX1NJWkU7CiAgICAKICAgIC8vIFNob290aW5nCiAgICBpZiAoKGtleXNbJyAnXSB8fCBrZXlzWzMyXSkgJiYgcGxheWVyLndlYXBvbl9jb29sZG93biA8PSAwKSB7CiAgICAgICAgY3JlYXRlX3Byb2plY3RpbGUocGxheWVyLngsIHBsYXllci55LCBwbGF5ZXIueiwgcGxheWVyLnJvdGF0aW9uLCAxKTsKICAgICAgICBwbGF5ZXIud2VhcG9uX2Nvb2xkb3duID0gMC4yZjsgLy8gMjAwbXMgY29vbGRvd24KICAgIH0KfQoKLy8gRGlzcGxheSBmdW5jdGlvbgp2b2lkIGRpc3BsYXkoKSB7CiAgICBnbENsZWFyKEdMX0NPTE9SX0JVRkZFUl9CSVQgfCBHTF9ERVBUSF9CVUZGRVJfQklUKTsKICAgIGdsTG9hZElkZW50aXR5KCk7CiAgICAKICAgIC8vIFNldCB1cCBjYW1lcmEKICAgIGZsb2F0IGNhbV94ID0gcGxheWVyLnggKyBjYW1lcmFfZGlzdGFuY2UgKiBzaW4oY2FtZXJhX2FuZ2xlX3kgKiBNX1BJIC8gMTgwLjBmKSAqIGNvcyhjYW1lcmFfYW5nbGVfeCAqIE1fUEkgLyAxODAuMGYpOwogICAgZmxvYXQgY2FtX3kgPSBwbGF5ZXIueSArIGNhbWVyYV9kaXN0YW5jZSAqIHNpbihjYW1lcmFfYW5nbGVfeCAqIE1fUEkgLyAxODAuMGYpOwogICAgZmxvYXQgY2FtX3ogPSBwbGF5ZXIueiArIGNhbWVyYV9kaXN0YW5jZSAqIGNvcyhjYW1lcmFfYW5nbGVfeSAqIE1fUEkgLyAxODAuMGYpICogY29zKGNhbWVyYV9hbmdsZV94ICogTV9QSSAvIDE4MC4wZik7CiAgICAKICAgIGdsdUxvb2tBdChjYW1feCwgY2FtX3ksIGNhbV96LCBwbGF5ZXIueCwgcGxheWVyLnksIHBsYXllci56LCAwLCAxLCAwKTsKICAgIAogICAgLy8gRW5hYmxlIGxpZ2h0aW5nCiAgICBnbEVuYWJsZShHTF9MSUdIVElORyk7CiAgICBnbEVuYWJsZShHTF9MSUdIVDApOwogICAgCiAgICBmbG9hdCBsaWdodF9wb3NbXSA9IHsxMC4wZiwgMjAuMGYsIDEwLjBmLCAxLjBmfTsKICAgIGZsb2F0IGxpZ2h0X2NvbG9yW10gPSB7MS4wZiwgMS4wZiwgMC45ZiwgMS4wZn07CiAgICBmbG9hdCBhbWJpZW50W10gPSB7MC4zZiwgMC4zZiwgMC40ZiwgMS4wZn07CiAgICAKICAgIGdsTGlnaHRmdihHTF9MSUdIVDAsIEdMX1BPU0lUSU9OLCBsaWdodF9wb3MpOwogICAgZ2xMaWdodGZ2KEdMX0xJR0hUMCwgR0xfRElGRlVTRSwgbGlnaHRfY29sb3IpOwogICAgZ2xMaWdodGZ2KEdMX0xJR0hUMCwgR0xfQU1CSUVOVCwgYW1iaWVudCk7CiAgICAKICAgIGRyYXdfc2t5Ym94KCk7CiAgICBkcmF3X3RlcnJhaW4oKTsKICAgIGRyYXdfcGxheWVyKCk7CiAgICBkcmF3X2VuZW1pZXMoKTsKICAgIAogICAgZ2xEaXNhYmxlKEdMX0xJR0hUSU5HKTsKICAgIGRyYXdfcHJvamVjdGlsZXMoKTsKICAgIGRyYXdfaHVkKCk7CiAgICAKICAgIGdsdXRTd2FwQnVmZmVycygpOwp9CgovLyBLZXlib2FyZCBpbnB1dAp2b2lkIGtleWJvYXJkKHVuc2lnbmVkIGNoYXIga2V5LCBpbnQgeCwgaW50IHkpIHsKICAgIGtleXNba2V5XSA9IDE7CiAgICBpZiAoa2V5ID09IDI3KSBleGl0KDApOyAvLyBFU0MgdG8gcXVpdAp9Cgp2b2lkIGtleWJvYXJkX3VwKHVuc2lnbmVkIGNoYXIga2V5LCBpbnQgeCwgaW50IHkpIHsKICAgIGtleXNba2V5XSA9IDA7Cn0KCi8vIE1vdXNlIGlucHV0IGZvciBjYW1lcmEgY29udHJvbAp2b2lkIG1vdXNlX21vdGlvbihpbnQgeCwgaW50IHkpIHsKICAgIGlmIChtb3VzZV94ICE9IC0xKSB7CiAgICAgICAgY2FtZXJhX2FuZ2xlX3kgKz0gKHggLSBtb3VzZV94KSAqIDAuNWY7CiAgICAgICAgY2FtZXJhX2FuZ2xlX3ggKz0gKHkgLSBtb3VzZV95KSAqIDAuNWY7CiAgICAgICAgCiAgICAgICAgaWYgKGNhbWVyYV9hbmdsZV94ID4gODAuMGYpIGNhbWVyYV9hbmdsZV94ID0gODAuMGY7CiAgICAgICAgaWYgKGNhbWVyYV9hbmdsZV94IDwgLTgwLjBmKSBjYW1lcmFfYW5nbGVfeCA9IC04MC4wZjsKICAgIH0KICAgIG1vdXNlX3ggPSB4OwogICAgbW91c2VfeSA9IHk7Cn0KCi8vIFRpbWVyIGZ1bmN0aW9uIGZvciBhbmltYXRpb24Kdm9pZCB0aW1lcihpbnQgdmFsdWUpIHsKICAgIGhhbmRsZV9tb3ZlbWVudCgpOwogICAgdXBkYXRlX2dhbWUoKTsKICAgIGdsdXRQb3N0UmVkaXNwbGF5KCk7CiAgICBnbHV0VGltZXJGdW5jKDE2LCB0aW1lciwgMCk7IC8vIDYwIEZQUwp9CgovLyBSZXNoYXBlIGZ1bmN0aW9uCnZvaWQgcmVzaGFwZShpbnQgdywgaW50IGgpIHsKICAgIGdsVmlld3BvcnQoMCwgMCwgdywgaCk7CiAgICBnbE1hdHJpeE1vZGUoR0xfUFJPSkVDVElPTik7CiAgICBnbExvYWRJZGVudGl0eSgpOwogICAgZ2x1UGVyc3BlY3RpdmUoNDUuMCwgKGZsb2F0KXcvaCwgMC4xLCAxMDAwLjApOwogICAgZ2xNYXRyaXhNb2RlKEdMX01PREVMVklFVyk7Cn0KCi8vIEluaXRpYWxpemUgT3BlbkdMCnZvaWQgaW5pdF9vcGVuZ2woKSB7CiAgICBnbEVuYWJsZShHTF9ERVBUSF9URVNUKTsKICAgIGdsRW5hYmxlKEdMX0JMRU5EKTsKICAgIGdsQmxlbmRGdW5jKEdMX1NSQ19BTFBIQSwgR0xfT05FX01JTlVTX1NSQ19BTFBIQSk7CiAgICBnbEVuYWJsZShHTF9DT0xPUl9NQVRFUklBTCk7CiAgICBnbENvbG9yTWF0ZXJpYWwoR0xfRlJPTlRfQU5EX0JBQ0ssIEdMX0FNQklFTlRfQU5EX0RJRkZVU0UpOwogICAgZ2xDbGVhckNvbG9yKDAuNWYsIDAuN2YsIDEuMGYsIDEuMGYpOwogICAgCiAgICBtb3VzZV94ID0gbW91c2VfeSA9IC0xOwp9CgppbnQgbWFpbihpbnQgYXJnYywgY2hhcioqIGFyZ3YpIHsKICAgIHByaW50ZigiPT09IE9wZW4gV29ybGQgQ29tYmF0IEdhbWUgPT09XG4iKTsKICAgIHByaW50ZigiQ29udHJvbHM6XG4iKTsKICAgIHByaW50ZigiVy9TIC0gTW92ZSBGb3J3YXJkL0JhY2t3YXJkXG4iKTsKICAgIHByaW50ZigiQS9EIC0gVHVybiBMZWZ0L1JpZ2h0XG4iKTsKICAgIHByaW50ZigiU3BhY2UgLSBTaG9vdFxuIik7CiAgICBwcmludGYoIk1vdXNlIC0gQ29udHJvbCBDYW1lcmFcbiIpOwogICAgcHJpbnRmKCJFU0MgLSBRdWl0XG5cbiIpOwogICAgCiAgICBnbHV0SW5pdCgmYXJnYywgYXJndik7CiAgICBnbHV0SW5pdERpc3BsYXlNb2RlKEdMVVRfRE9VQkxFIHwgR0xVVF9SR0IgfCBHTFVUX0RFUFRIKTsKICAgIGdsdXRJbml0V2luZG93U2l6ZSg4MDAsIDYwMCk7CiAgICBnbHV0Q3JlYXRlV2luZG93KCJPcGVuIFdvcmxkIENvbWJhdCBHYW1lIik7CiAgICAKICAgIGluaXRfb3BlbmdsKCk7CiAgICBpbml0X2dhbWUoKTsKICAgIAogICAgZ2x1dERpc3BsYXlGdW5jKGRpc3BsYXkpOwogICAgZ2x1dFJlc2hhcGVGdW5jKHJlc2hhcGUpOwogICAgZ2x1dEtleWJvYXJkRnVuYyhrZXlib2FyZCk7CiAgICBnbHV0S2V5Ym9hcmRVcEZ1bmMoa2V5Ym9hcmRfdXApOwogICAgZ2x1dFBhc3NpdmVNb3Rpb25GdW5jKG1vdXNlX21vdGlvbik7CiAgICBnbHV0TW90aW9uRnVuYyhtb3VzZV9tb3Rpb24pOwogICAgZ2x1dFRpbWVyRnVuYygwLCB0aW1lciwgMCk7CiAgICAKICAgIHByaW50ZigiR2FtZSBzdGFydGVkISBEZWZlbmQgeW91cnNlbGYgYWdhaW5zdCB0aGUgcmVkIGVuZW1pZXMhXG4iKTsKICAgIAogICAgZ2x1dE1haW5Mb29wKCk7CiAgICByZXR1cm4gMDsKfQ==
#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;
}