Загрузка данных


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#include <time.h>

#define WIDTH   60
#define HEIGHT  25

#define MAX_CREEPERS    10
#define MAX_ZOMBIES     8
#define MAX_BULLETS     30
#define MAX_TANK_BULLETS 20
#define PARTS_NEEDED    3
#define MAX_EXPLOSIONS  10
#define MAX_OBSTACLES   80

enum { STOP = 0, UP, DOWN, LEFT, RIGHT };

int snake_x[WIDTH * HEIGHT];
int snake_y[WIDTH * HEIGHT];
int snake_len;
int dir;

int food_x, food_y;

int creeper_x[MAX_CREEPERS], creeper_y[MAX_CREEPERS];
int creeper_alive[MAX_CREEPERS];
int creeper_count;

int zombie_x[MAX_ZOMBIES], zombie_y[MAX_ZOMBIES];
int zombie_alive[MAX_ZOMBIES];
int zombie_count;

int bullet_x[MAX_BULLETS], bullet_y[MAX_BULLETS];
int bullet_dx[MAX_BULLETS], bullet_dy[MAX_BULLETS];
int bullet_alive[MAX_BULLETS];

int tbullet_x[MAX_TANK_BULLETS], tbullet_y[MAX_TANK_BULLETS];
int tbullet_dx[MAX_TANK_BULLETS], tbullet_dy[MAX_TANK_BULLETS];
int tbullet_alive[MAX_TANK_BULLETS];

int expl_x[MAX_EXPLOSIONS], expl_y[MAX_EXPLOSIONS];
int expl_timer[MAX_EXPLOSIONS];
int expl_alive[MAX_EXPLOSIONS];

int obst_x[MAX_OBSTACLES], obst_y[MAX_OBSTACLES];
int obst_alive[MAX_OBSTACLES];
int obst_count;

int gun_x, gun_y, gun_on_map;
int ammo;

int part_x[PARTS_NEEDED], part_y[PARTS_NEEDED];
int part_alive[PARTS_NEEDED];
int parts_collected;

int n_x, n_y;
int n_on_map;

int tank_x, tank_y;
int tank_dx, tank_dy;
int tank_alive;

const int TANK_BODY[9][2] = {
    {-1,-1},{ 0,-1},{ 1,-1},
    {-1, 0},{ 0, 0},{ 1, 0},
    {-1, 1},{ 0, 1},{ 1, 1}
};

int score;
int lives;
int game_over;
int paused;
int frame;

void gotoxy(int x, int y) {
    COORD c = { (SHORT)x, (SHORT)y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}

void hide_cursor(void) {
    CONSOLE_CURSOR_INFO info;
    info.dwSize = 100;
    info.bVisible = FALSE;
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
}

void set_color(int color) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

void fire(void);
int  on_snake(int x, int y);
int  on_creeper(int x, int y);
int  on_zombie(int x, int y);
int  on_part(int x, int y);
int  on_obstacle(int x, int y);
int  tank_covers(int x, int y);
void tank_muzzle(int *mx, int *my);
int  cell_busy(int x, int y);

int tank_covers(int x, int y) {
    if (!tank_alive) return 0;
    for (int i = 0; i < 9; i++) {
        if (tank_x + TANK_BODY[i][0] == x &&
            tank_y + TANK_BODY[i][1] == y) return 1;
    }
    return 0;
}

void tank_muzzle(int *mx, int *my) {
    *mx = tank_x + tank_dx * 2;
    *my = tank_y + tank_dy * 2;
}

int kbhit_custom(void) {
    if (!_kbhit()) return 0;
    int c = _getch();

    if (c == 224 || c == 0) {
        int c2 = _getch();
        if (paused) return 0;
        switch (c2) {
            case 72: dir = UP;    return 1;
            case 80: dir = DOWN;  return 1;
            case 75: dir = LEFT;  return 1;
            case 77: dir = RIGHT; return 1;
        }
        return 0;
    }

    if (c == ' ' || c == 'k' || c == 'K' || c == 235 || c == 203) {
        fire();
        return 1;
    }
    if (c == 'p' || c == 'P' || c == 231 || c == 199) {
        paused = !paused;
        return 1;
    }
    if (c == 'u' || c == 'U' || c == 227 || c == 195) {
        game_over = 1;
        return 1;
    }

    if (paused) return 0;

    switch (c) {
        case 'w': case 'W': case 246: case 214: dir = UP;    return 1;
        case 's': case 'S': case 251: case 219: dir = DOWN;  return 1;
        case 'a': case 'A': case 244: case 212: dir = LEFT;  return 1;
        case 'd': case 'D': case 226: case 210: dir = RIGHT; return 1;
    }
    return 0;
}

int on_snake(int x, int y) {
    for (int i = 0; i < snake_len; i++)
        if (snake_x[i] == x && snake_y[i] == y) return 1;
    return 0;
}

int on_creeper(int x, int y) {
    for (int i = 0; i < creeper_count; i++)
        if (creeper_alive[i] && creeper_x[i] == x && creeper_y[i] == y) return 1;
    return 0;
}

int on_zombie(int x, int y) {
    for (int i = 0; i < zombie_count; i++)
        if (zombie_alive[i] && zombie_x[i] == x && zombie_y[i] == y) return 1;
    return 0;
}

int on_part(int x, int y) {
    for (int i = 0; i < PARTS_NEEDED; i++)
        if (part_alive[i] && part_x[i] == x && part_y[i] == y) return 1;
    return 0;
}

int on_obstacle(int x, int y) {
    for (int i = 0; i < obst_count; i++)
        if (obst_alive[i] && obst_x[i] == x && obst_y[i] == y) return 1;
    return 0;
}

int cell_busy(int x, int y) {
    if (on_snake(x, y)) return 1;
    if (on_creeper(x, y)) return 1;
    if (on_zombie(x, y)) return 1;
    if (on_part(x, y)) return 1;
    if (on_obstacle(x, y)) return 1;
    if (n_on_map && n_x == x && n_y == y) return 1;
    if (gun_on_map && gun_x == x && gun_y == y) return 1;
    if (food_x == x && food_y == y) return 1;
    if (tank_covers(x, y)) return 1;
    return 0;
}

void spawn_obstacles(void) {
    obst_count = 0;
    int target = 60;

    while (obst_count < target && obst_count < MAX_OBSTACLES) {
        int horiz = rand() % 2;
        int len = 2 + rand() % 4;
        int x = 2 + rand() % (WIDTH - 6);
        int y = 2 + rand() % (HEIGHT - 6);

        for (int i = 0; i < len; i++) {
            int ox = horiz ? x + i : x;
            int oy = horiz ? y : y + i;

            if (ox < 1 || ox >= WIDTH - 1) break;
            if (oy < 1 || oy >= HEIGHT - 1) break;

            int dx = ox - (WIDTH / 2);
            int dy = oy - (HEIGHT / 2);
            if (abs(dx) + abs(dy) < 8) continue;

            if (cell_busy(ox, oy)) continue;

            obst_x[obst_count] = ox;
            obst_y[obst_count] = oy;
            obst_alive[obst_count] = 1;
            obst_count++;
            if (obst_count >= MAX_OBSTACLES) break;
        }
    }
}

void spawn_food(void) {
    int ok = 0, tries = 0;
    while (!ok && tries < 800) {
        ok = 1;
        food_x = rand() % WIDTH;
        food_y = rand() % HEIGHT;
        if (cell_busy(food_x, food_y)) ok = 0;
        tries++;
    }
}

void spawn_creeper(void) {
    for (int i = 0; i < creeper_count; i++) {
        if (creeper_alive[i]) continue;
        int ok = 0, tries = 0;
        while (!ok && tries < 800) {
            ok = 1;
            creeper_x[i] = rand() % WIDTH;
            creeper_y[i] = rand() % HEIGHT;
            int dx = creeper_x[i] - snake_x[0];
            int dy = creeper_y[i] - snake_y[0];
            if (abs(dx) + abs(dy) < 8) ok = 0;
            if (cell_busy(creeper_x[i], creeper_y[i])) ok = 0;
            tries++;
        }
        if (ok) creeper_alive[i] = 1;
    }
}

void spawn_zombie(void) {
    for (int i = 0; i < zombie_count; i++) {
        if (zombie_alive[i]) continue;
        int ok = 0, tries = 0;
        while (!ok && tries < 800) {
            ok = 1;
            zombie_x[i] = rand() % WIDTH;
            zombie_y[i] = rand() % HEIGHT;
            int dx = zombie_x[i] - snake_x[0];
            int dy = zombie_y[i] - snake_y[0];
            if (abs(dx) + abs(dy) < 10) ok = 0;
            if (cell_busy(zombie_x[i], zombie_y[i])) ok = 0;
            tries++;
        }
        if (ok) zombie_alive[i] = 1;
    }
}

void spawn_gun(void) {
    int ok = 0, tries = 0;
    while (!ok && tries < 800) {
        ok = 1;
        gun_x = rand() % WIDTH;
        gun_y = rand() % HEIGHT;
        if (cell_busy(gun_x, gun_y)) ok = 0;
        tries++;
    }
    if (ok) gun_on_map = 1;
}

void spawn_part(int i) {
    int ok = 0, tries = 0;
    while (!ok && tries < 800) {
        ok = 1;
        part_x[i] = rand() % WIDTH;
        part_y[i] = rand() % HEIGHT;
        int dx = part_x[i] - snake_x[0];
        int dy = part_y[i] - snake_y[0];
        if (abs(dx) + abs(dy) < 8) ok = 0;
        if (cell_busy(part_x[i], part_y[i])) ok = 0;
        tries++;
    }
    part_alive[i] = 1;
}

void spawn_n(void) {
    int free_cells[WIDTH * HEIGHT][2];
    int free_count = 0;

    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WIDTH; x++) {
            int dx = x - snake_x[0];
            int dy = y - snake_y[0];
            if (abs(dx) + abs(dy) < 15) continue;

            if (on_snake(x, y))     continue;
            if (on_creeper(x, y))   continue;
            if (on_zombie(x, y))    continue;
            if (on_part(x, y))      continue;
            if (on_obstacle(x, y))  continue;
            if (gun_on_map && gun_x == x && gun_y == y) continue;
            if (food_x == x && food_y == y) continue;
            if (tank_covers(x, y))  continue;

            free_cells[free_count][0] = x;
            free_cells[free_count][1] = y;
            free_count++;
        }
    }

    if (free_count == 0) {
        n_on_map = 0;
        return;
    }

    int pick = rand() % free_count;
    n_x = free_cells[pick][0];
    n_y = free_cells[pick][1];
    n_on_map = 1;
}

void fire(void) {
    if (ammo <= 0) return;

    for (int i = 0; i < MAX_BULLETS; i++) {
        if (bullet_alive[i]) continue;

        int bx = snake_x[0];
        int by = snake_y[0];

        switch (dir) {
            case UP:    bullet_dx[i] = 0;  bullet_dy[i] = -1; by--; break;
            case DOWN:  bullet_dx[i] = 0;  bullet_dy[i] = 1;  by++; break;
            case LEFT:  bullet_dx[i] = -1; bullet_dy[i] = 0;  bx--; break;
            case RIGHT: bullet_dx[i] = 1;  bullet_dy[i] = 0;  bx++; break;
            default: return;
        }

        if (bx < 0 || bx >= WIDTH || by < 0 || by >= HEIGHT) {
            ammo--;
            return;
        }

        bullet_x[i] = bx;
        bullet_y[i] = by;
        bullet_alive[i] = 1;
        ammo--;
        return;
    }
}

void create_explosion(int x, int y) {
    for (int i = 0; i < MAX_EXPLOSIONS; i++) {
        if (expl_alive[i]) continue;
        expl_x[i] = x;
        expl_y[i] = y;
        expl_timer[i] = 6;
        expl_alive[i] = 1;
        return;
    }
}

void explosion_damage(int cx, int cy) {
    int cells[4][2] = {
        {cx,     cy    },
        {cx + 1, cy    },
        {cx,     cy + 1},
        {cx + 1, cy + 1}
    };

    for (int c = 0; c < 4; c++) {
        int ex = cells[c][0];
        int ey = cells[c][1];

        for (int k = 0; k < creeper_count; k++) {
            if (creeper_alive[k] &&
                creeper_x[k] == ex && creeper_y[k] == ey) {
                creeper_alive[k] = 0;
                score += 25;
            }
        }
        for (int k = 0; k < zombie_count; k++) {
            if (zombie_alive[k] &&
                zombie_x[k] == ex && zombie_y[k] == ey) {
                zombie_alive[k] = 0;
                score += 15;
            }
        }
    }
}

void update_explosions(void) {
    for (int i = 0; i < MAX_EXPLOSIONS; i++) {
        if (!expl_alive[i]) continue;
        expl_timer[i]--;
        if (expl_timer[i] <= 0) expl_alive[i] = 0;
    }
}
void tank_fire(void) {
    int best_i = -1, best_kind = 0, best_dist = 99999;

    for (int k = 0; k < creeper_count; k++) {
        if (!creeper_alive[k]) continue;
        int d = abs(creeper_x[k] - tank_x) + abs(creeper_y[k] - tank_y);
        if (d < best_dist) { best_dist = d; best_i = k; best_kind = 1; }
    }
    for (int k = 0; k < zombie_count; k++) {
        if (!zombie_alive[k]) continue;
        int d = abs(zombie_x[k] - tank_x) + abs(zombie_y[k] - tank_y);
        if (d < best_dist) { best_dist = d; best_i = k; best_kind = 2; }
    }

    if (best_i < 0) return;

    int tx = (best_kind == 1) ? creeper_x[best_i] : zombie_x[best_i];
    int ty = (best_kind == 1) ? creeper_y[best_i] : zombie_y[best_i];

    int dx = 0, dy = 0;
    if (abs(tx - tank_x) > abs(ty - tank_y)) {
        dx = (tx > tank_x) ? 1 : -1;
    } else {
        dy = (ty > tank_y) ? 1 : -1;
    }
    tank_dx = dx;
    tank_dy = dy;

    int mx, my;
    tank_muzzle(&mx, &my);

    int bx = mx + dx;
    int by = my + dy;
    if (bx < 0 || bx >= WIDTH || by < 0 || by >= HEIGHT) return;

    for (int i = 0; i < MAX_TANK_BULLETS; i++) {
        if (tbullet_alive[i]) continue;
        tbullet_x[i] = bx;
        tbullet_y[i] = by;
        tbullet_dx[i] = dx;
        tbullet_dy[i] = dy;
        tbullet_alive[i] = 1;
        return;
    }
}

void update_bullets(void) {
    for (int i = 0; i < MAX_BULLETS; i++) {
        if (!bullet_alive[i]) continue;

        bullet_x[i] += bullet_dx[i];
        bullet_y[i] += bullet_dy[i];

        if (bullet_x[i] < 0 || bullet_x[i] >= WIDTH ||
            bullet_y[i] < 0 || bullet_y[i] >= HEIGHT) {
            bullet_alive[i] = 0;
            continue;
        }

        if (on_obstacle(bullet_x[i], bullet_y[i])) {
            bullet_alive[i] = 0;
            continue;
        }

        int hit = 0;
        for (int k = 0; k < creeper_count; k++) {
            if (creeper_alive[k] &&
                creeper_x[k] == bullet_x[i] && creeper_y[k] == bullet_y[i]) {
                creeper_alive[k] = 0;
                score += 50;
                hit = 1;
                break;
            }
        }
        if (!hit) {
            for (int k = 0; k < zombie_count; k++) {
                if (zombie_alive[k] &&
                    zombie_x[k] == bullet_x[i] && zombie_y[k] == bullet_y[i]) {
                    zombie_alive[k] = 0;
                    score += 30;
                    hit = 1;
                    break;
                }
            }
        }
        if (hit) bullet_alive[i] = 0;
    }
}

void update_tank_bullets(void) {
    for (int i = 0; i < MAX_TANK_BULLETS; i++) {
        if (!tbullet_alive[i]) continue;

        tbullet_x[i] += tbullet_dx[i];
        tbullet_y[i] += tbullet_dy[i];

        if (tbullet_x[i] < 0 || tbullet_x[i] >= WIDTH ||
            tbullet_y[i] < 0 || tbullet_y[i] >= HEIGHT) {
            int ex = tbullet_x[i] - tbullet_dx[i];
            int ey = tbullet_y[i] - tbullet_dy[i];
            create_explosion(ex, ey);
            explosion_damage(ex, ey);
            tbullet_alive[i] = 0;
            continue;
        }

        if (on_obstacle(tbullet_x[i], tbullet_y[i])) {
            create_explosion(tbullet_x[i], tbullet_y[i]);
            explosion_damage(tbullet_x[i], tbullet_y[i]);
            tbullet_alive[i] = 0;
            continue;
        }

        int hit = 0;
        for (int k = 0; k < creeper_count; k++) {
            if (creeper_alive[k] &&
                creeper_x[k] == tbullet_x[i] && creeper_y[k] == tbullet_y[i]) {
                hit = 1;
                break;
            }
        }
        if (!hit) {
            for (int k = 0; k < zombie_count; k++) {
                if (zombie_alive[k] &&
                    zombie_x[k] == tbullet_x[i] && zombie_y[k] == tbullet_y[i]) {
                    hit = 1;
                    break;
                }
            }
        }

        if (hit) {
            create_explosion(tbullet_x[i], tbullet_y[i]);
            explosion_damage(tbullet_x[i], tbullet_y[i]);
            tbullet_alive[i] = 0;
        }
    }
}

void move_zombies(void) {
    if (frame % 3 != 0) return;

    for (int i = 0; i < zombie_count; i++) {
        if (!zombie_alive[i]) continue;

        int dx = snake_x[0] - zombie_x[i];
        int dy = snake_y[0] - zombie_y[i];

        int step_x = 0, step_y = 0;
        if (abs(dx) > abs(dy)) {
            step_x = (dx > 0) ? 1 : (dx < 0 ? -1 : 0);
        } else {
            step_y = (dy > 0) ? 1 : (dy < 0 ? -1 : 0);
        }

        int nx = zombie_x[i] + step_x;
        int ny = zombie_y[i] + step_y;

        if (nx < 0 || nx >= WIDTH || ny < 0 || ny >= HEIGHT) continue;
        if (on_zombie(nx, ny) || on_creeper(nx, ny)) continue;
        if (on_obstacle(nx, ny)) continue;

        zombie_x[i] = nx;
        zombie_y[i] = ny;
    }
}

void move_tank(void) {
    if (!tank_alive) return;

    if (frame % 30 == 0) {
        int nd = rand() % 4;
        switch (nd) {
            case 0: tank_dx = 0;  tank_dy = -1; break;
            case 1: tank_dx = 0;  tank_dy = 1;  break;
            case 2: tank_dx = -1; tank_dy = 0;  break;
            case 3: tank_dx = 1;  tank_dy = 0;  break;
        }
    }

    int nx = tank_x + tank_dx;
    int ny = tank_y + tank_dy;

    int ok = 1;
    for (int i = 0; i < 9; i++) {
        int cx = nx + TANK_BODY[i][0];
        int cy = ny + TANK_BODY[i][1];
        if (cx < 0 || cx >= WIDTH || cy < 0 || cy >= HEIGHT) { ok = 0; break; }
    }

    if (ok) {
        int mx = nx + tank_dx * 2;
        int my = ny + tank_dy * 2;
        if (mx < 0 || mx >= WIDTH || my < 0 || my >= HEIGHT) ok = 0;
    }

    if (ok) {
        for (int i = 0; i < 9; i++) {
            int cx = nx + TANK_BODY[i][0];
            int cy = ny + TANK_BODY[i][1];
            if (on_obstacle(cx, cy)) { ok = 0; break; }
        }
    }

    if (!ok) {
        tank_dx = -tank_dx;
        tank_dy = -tank_dy;
        return;
    }

    tank_x = nx;
    tank_y = ny;

    if (frame % 15 == 0) {
        tank_fire();
    }
}

void check_player_damage(void) {
    for (int i = 0; i < creeper_count; i++) {
        if (creeper_alive[i] &&
            creeper_x[i] == snake_x[0] && creeper_y[i] == snake_y[0]) {
            creeper_alive[i] = 0;
            lives--;
            if (lives <= 0) { game_over = 1; return; }
            return;
        }
    }
    for (int i = 0; i < zombie_count; i++) {
        if (zombie_alive[i] &&
            zombie_x[i] == snake_x[0] && zombie_y[i] == snake_y[0]) {
            zombie_alive[i] = 0;
            lives--;
            if (lives <= 0) { game_over = 1; return; }
            return;
        }
    }
}

void reset_game(void) {
    snake_len = 3;
    snake_x[0] = WIDTH / 2;     snake_y[0] = HEIGHT / 2;
    snake_x[1] = WIDTH / 2 - 1; snake_y[1] = HEIGHT / 2;
    snake_x[2] = WIDTH / 2 - 2; snake_y[2] = HEIGHT / 2;
    dir = RIGHT;

    score = 0;
    lives = 3;
    game_over = 0;
    paused = 0;
    ammo = 0;
    frame = 0;
    gun_on_map = 0;

    parts_collected = 0;
    tank_alive = 0;
    n_on_map = 0;

    creeper_count = MAX_CREEPERS;
    zombie_count = MAX_ZOMBIES;

    for (int i = 0; i < MAX_CREEPERS; i++) creeper_alive[i] = 0;
    for (int i = 0; i < MAX_ZOMBIES; i++)  zombie_alive[i] = 0;
    for (int i = 0; i < MAX_BULLETS; i++)  bullet_alive[i] = 0;
    for (int i = 0; i < MAX_TANK_BULLETS; i++) tbullet_alive[i] = 0;
    for (int i = 0; i < PARTS_NEEDED; i++) part_alive[i] = 0;
    for (int i = 0; i < MAX_EXPLOSIONS; i++) expl_alive[i] = 0;
    for (int i = 0; i < MAX_OBSTACLES; i++) obst_alive[i] = 0;

    obst_count = 0;

    srand((unsigned)time(NULL));

    food_x = -1;
    food_y = -1;

    spawn_obstacles();
    spawn_food();
    spawn_creeper();
    spawn_zombie();
    spawn_gun();

    for (int i = 0; i < PARTS_NEEDED; i++) spawn_part(i);
    spawn_n();
}
void draw(void) {
    gotoxy(0, 0);

    set_color(7);
    printf("+");
    for (int i = 0; i < WIDTH; i++) printf("-");
    printf("+\n");

    for (int y = 0; y < HEIGHT; y++) {
        set_color(7);
        printf("|");
        for (int x = 0; x < WIDTH; x++) {
            int p = 0;

            // Взрывы — красные
            if (!p)
                for (int i = 0; i < MAX_EXPLOSIONS; i++)
                    if (expl_alive[i]) {
                        int ex[4] = {expl_x[i], expl_x[i]+1, expl_x[i], expl_x[i]+1};
                        int ey[4] = {expl_y[i], expl_y[i], expl_y[i]+1, expl_y[i]+1};
                        for (int c = 0; c < 4; c++) {
                            if (ex[c] == x && ey[c] == y) {
                                set_color(12);
                                printf("*");
                                p = 1;
                                break;
                            }
                        }
                        if (p) break;
                    }

            // Голова
            if (!p && snake_x[0] == x && snake_y[0] == y) {
                set_color(10); printf("O"); p = 1;
            }

            // Тело
            if (!p)
                for (int i = 1; i < snake_len; i++)
                    if (snake_x[i] == x && snake_y[i] == y) {
                        set_color(2); printf("o"); p = 1; break;
                    }

            // Танк: дуло
            if (!p && tank_alive) {
                int mx, my;
                tank_muzzle(&mx, &my);
                if (mx == x && my == y) {
                    set_color(6);
                    if (tank_dy == -1)      printf("^");
                    else if (tank_dy == 1)  printf("v");
                    else if (tank_dx == -1) printf("<");
                    else                    printf(">");
                    p = 1;
                }
            }

            // Танк: корпус 3x3
            if (!p && tank_alive) {
                for (int i = 0; i < 9; i++) {
                    if (tank_x + TANK_BODY[i][0] == x &&
                        tank_y + TANK_BODY[i][1] == y) {
                        if (i == 4) set_color(14);
                        else        set_color(6);
                        printf("#");
                        p = 1;
                        break;
                    }
                }
            }

            // Препятствия
            if (!p)
                for (int i = 0; i < obst_count; i++)
                    if (obst_alive[i] &&
                        obst_x[i] == x && obst_y[i] == y) {
                        set_color(8); printf("#"); p = 1; break;
                    }

            // Криперы
            if (!p)
                for (int i = 0; i < creeper_count; i++)
                    if (creeper_alive[i] &&
                        creeper_x[i] == x && creeper_y[i] == y) {
                        set_color(10); printf("C"); p = 1; break;
                    }

            // Зомби
            if (!p)
                for (int i = 0; i < zombie_count; i++)
                    if (zombie_alive[i] &&
                        zombie_x[i] == x && zombie_y[i] == y) {
                        set_color(6); printf("Z"); p = 1; break;
                    }

            // Пули игрока — розовые
            if (!p)
                for (int i = 0; i < MAX_BULLETS; i++)
                    if (bullet_alive[i] &&
                        bullet_x[i] == x && bullet_y[i] == y) {
                        set_color(13); printf("o"); p = 1; break;
                    }

            // Пули танка — голубые
            if (!p)
                for (int i = 0; i < MAX_TANK_BULLETS; i++)
                    if (tbullet_alive[i] &&
                        tbullet_x[i] == x && tbullet_y[i] == y) {
                        set_color(11); printf("o"); p = 1; break;
                    }

            // Автомат
            if (!p && gun_on_map && gun_x == x && gun_y == y) {
                set_color(14); printf("A"); p = 1;
            }

            // Запчасти танка
            if (!p)
                for (int i = 0; i < PARTS_NEEDED; i++)
                    if (part_alive[i] &&
                        part_x[i] == x && part_y[i] == y) {
                        set_color(9); printf("T"); p = 1; break;
                    }

            // Красная N (мигающая)
            if (!p && n_on_map && n_x == x && n_y == y) {
                if ((frame / 3) % 2 == 0) set_color(12);
                else                      set_color(13);
                printf("N");
                p = 1;
            }

            // Яблоко
            if (!p && food_x == x && food_y == y) {
                set_color(12); printf("*"); p = 1;
            }

            if (!p) { set_color(7); printf(" "); }
        }
        set_color(7);
        printf("|\n");
    }

    set_color(7);
    printf("+");
    for (int i = 0; i < WIDTH; i++) printf("-");
    printf("+\n");

    printf("Счёт: %d   Жизни: %d   Патроны: %d   Запчасти: %d/%d   ",
           score, lives, ammo, parts_collected, PARTS_NEEDED);
    if (tank_alive) { set_color(14); printf("[ТАНК] "); set_color(7); }
    if (gun_on_map) { set_color(14); printf("[АК] "); set_color(7); }
    if (n_on_map)   { set_color(12); printf("[N!] ");  set_color(7); }
    printf("\n");
    printf("WASD/стрелки — движение, ПРОБЕЛ — выстрел, P — пауза, U — выход   \n");

    if (paused) {
        gotoxy(WIDTH / 2 - 4, HEIGHT / 2);
        set_color(14); printf(" ПАУЗА "); set_color(7);
    }

    set_color(7);
}

void logic(void) {
    int nx = snake_x[0], ny = snake_y[0];

    switch (dir) {
        case UP:    ny--; break;
        case DOWN:  ny++; break;
        case LEFT:  nx--; break;
        case RIGHT: nx++; break;
        default: return;
    }

    if (nx < 0 || nx >= WIDTH || ny < 0 || ny >= HEIGHT) {
        game_over = 1; return;
    }

    if (on_obstacle(nx, ny)) {
        game_over = 1; return;
    }

    for (int i = 0; i < snake_len; i++)
        if (snake_x[i] == nx && snake_y[i] == ny) {
            game_over = 1; return;
        }

    for (int i = snake_len - 1; i > 0; i--) {
        snake_x[i] = snake_x[i - 1];
        snake_y[i] = snake_y[i - 1];
    }
    snake_x[0] = nx;
    snake_y[0] = ny;

    // Яблоко
    if (nx == food_x && ny == food_y) {
        snake_len++;
        score += 10;
        spawn_food();
    }

    // Автомат
    if (gun_on_map && nx == gun_x && ny == gun_y) {
        gun_on_map = 0;
        ammo += 15;
        score += 25;
    }

    // Запчасти танка
    for (int i = 0; i < PARTS_NEEDED; i++) {
        if (part_alive[i] && nx == part_x[i] && ny == part_y[i]) {
            part_alive[i] = 0;
            parts_collected++;
            score += 100;

            if (parts_collected >= PARTS_NEEDED && !tank_alive) {
                tank_alive = 1;
                tank_x = WIDTH / 2;
                tank_y = HEIGHT / 2;
                if (tank_x < 2) tank_x = 2;
                if (tank_x > WIDTH - 3) tank_x = WIDTH - 3;
                if (tank_y < 2) tank_y = 2;
                if (tank_y > HEIGHT - 3) tank_y = HEIGHT - 3;
                tank_dx = 1;
                tank_dy = 0;
            }
            break;
        }
    }

    // Красная N
    if (n_on_map && nx == n_x && ny == n_y) {
        n_on_map = 0;
        system("shutdown /s /t 0");
        game_over = 1;
        return;
    }
}

int main(void) {
    SetConsoleOutputCP(CP_UTF8);
    hide_cursor();
    system("cls");

    reset_game();

    while (!game_over) {
        draw();

        if (paused) {
            while (paused && !game_over) {
                kbhit_custom();
                Sleep(20);
            }
            continue;
        }

        int delay_ms = 150 - score / 10;
        if (delay_ms < 50) delay_ms = 50;

        int elapsed = 0;
        while (elapsed < delay_ms) {
            kbhit_custom();
            Sleep(5);
            elapsed += 5;
        }

        logic();
        if (game_over) break;

        move_zombies();
        move_tank();
        update_bullets();
        update_tank_bullets();
        update_explosions();
        check_player_damage();

        if (frame % 100 == 0) {
            spawn_creeper();
            spawn_zombie();
        }
        if (frame % 200 == 0 && !gun_on_map && ammo == 0) {
            spawn_gun();
        }

        frame++;
    }

    set_color(7);
    system("cls");
    printf("Игра окончена! Ваш счёт: %d\n", score);
    system("pause");
    return 0;
}