// Multiplayer Maze FPS - 纯源代码版
// 仅需要 main.cpp 文件,无需项目配置

#include <iostream>
#include <conio.h>
#include <cstdlib>
#include <ctime>
#include <windows.h>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

// 兼容设置
#define getch _getch
#define kbhit _kbhit

const int MAP_WIDTH = 61;
const int MAP_HEIGHT = 21;
const int MAX_PLAYERS = 4;
const int MAX_ENEMIES = 10;
const int MAX_BULLETS = 30;

enum ControlScheme { WASD, TFGH, IJKL, ARROWS };

char map[MAP_HEIGHT][MAP_WIDTH];

struct Player {
    int x, y, hp, lives, score;
    int ammo[3], weapon, color;
    char dir;
    ControlScheme controls;
    bool active;
};

struct Enemy {
    int x, y, hp, type;
    bool active;
    int aiTimer;
};

struct Boss {
    int x, y, hp, maxHp, phase;
    bool active;
    int attackTimer;
    vector<pair<int,int> > minions;
} boss;

struct Bullet {
    int x, y, dx, dy, owner, type;
    bool active;
};

Player players[MAX_PLAYERS];
Enemy enemies[MAX_ENEMIES];
Bullet bullets[MAX_BULLETS];
int playerCount = 1;
int level = 1;
bool gameRunning = true;

// 生成迷宫
void generateMaze() {
    for(int y = 0; y < MAP_HEIGHT; y++)
        for(int x = 0; x < MAP_WIDTH; x++)
            map[y][x] = '#';

    stack<pair<int,int> > stk;
    int x = 1, y = 1;
    map[y][x] = ' ';
    stk.push(make_pair(x, y));

    while(!stk.empty()) {
        x = stk.top().first;
        y = stk.top().second;

        vector<int> dirs;
        if(y > 2 && map[y-2][x] == '#') dirs.push_back(0);
        if(x < MAP_WIDTH-3 && map[y][x+2] == '#') dirs.push_back(1);
        if(y < MAP_HEIGHT-3 && map[y+2][x] == '#') dirs.push_back(2);
        if(x > 2 && map[y][x-2] == '#') dirs.push_back(3);

        if(!dirs.empty()) {
            int dir = dirs[rand() % dirs.size()];
            switch(dir) {
                case 0: map[y-1][x] = ' '; y -= 2; break;
                case 1: map[y][x+1] = ' '; x += 2; break;
                case 2: map[y+1][x] = ' '; y += 2; break;
                case 3: map[y][x-1] = ' '; x -= 2; break;
            }
            map[y][x] = ' ';
            stk.push(make_pair(x, y));
        } else {
            stk.pop();
        }
    }
    map[1][1] = map[1][MAP_WIDTH-2] = ' ';
    map[MAP_HEIGHT-2][1] = map[MAP_HEIGHT-2][MAP_WIDTH-2] = ' ';
}

// 初始化玩家
void initPlayers(int count) {
    int colors[] = {14, 10, 13, 11};
    int pos[4][2] = {{1,1}, {MAP_WIDTH-2,1}, 
                     {1,MAP_HEIGHT-2}, {MAP_WIDTH-2,MAP_HEIGHT-2}};

    for(int i = 0; i < count; i++) {
        players[i] = {pos[i][0], pos[i][1], 100, 3, 0, 
                      {100,50,30}, 0, colors[i], '^', 
                      (ControlScheme)i, true};
    }
}

// 生成敌人
void spawnEnemy() {
    for(int i = 0; i < MAX_ENEMIES; i++) {
        if(!enemies[i].active) {
            int attempts = 0;
            do {
                enemies[i].x = 1 + rand() % (MAP_WIDTH-2);
                enemies[i].y = 1 + rand() % (MAP_HEIGHT-2);
                attempts++;
            } while(map[enemies[i].y][enemies[i].x] != ' ' && attempts < 100);

            if(attempts < 100) {
                enemies[i].hp = 2 + level;
                enemies[i].type = rand() % 2;
                enemies[i].aiTimer = 15 + rand() % 15;
                enemies[i].active = true;
            }
            break;
        }
    }
}

// 生成BOSS
void spawnBoss() {
    boss = {MAP_WIDTH/2, MAP_HEIGHT/2, 50+level*20, 
            50+level*20, 0, true, 30, {}};
}

// 射击
void shoot(int pid) {
    Player& p = players[pid];
    for(int i = 0; i < MAX_BULLETS; i++) {
        if(!bullets[i].active) {
            bullets[i] = {p.x, p.y, 0, 0, pid, p.weapon, true};
            switch(p.dir) {
                case '^': bullets[i].dy = -1; break;
                case 'v': bullets[i].dy = 1; break;
                case '<': bullets[i].dx = -1; break;
                case '>': bullets[i].dx = 1; break;
            }
            if(p.weapon > 0) {
                if(--p.ammo[p.weapon] <= 0) p.weapon = 0;
            }
            Beep(1000, 50);
            break;
        }
    }
}

// 更新游戏
void updateGame() {
    // 敌人逻辑
    for(int i = 0; i < MAX_ENEMIES; i++) {
        if(enemies[i].active && --enemies[i].aiTimer <= 0) {
            enemies[i].aiTimer = 15 + rand() % 20;
            int dir = rand() % 2;
            int& coord = dir ? enemies[i].x : enemies[i].y;
            int delta = (rand() % 2) ? 1 : -1;
            int newPos = coord + delta;
            if(newPos > 0 && newPos < (dir ? MAP_WIDTH : MAP_HEIGHT)-1 
               && map[dir ? enemies[i].y : newPos][dir ? newPos : enemies[i].x] == ' ') {
                coord = newPos;
            }

            for(int p = 0; p < playerCount; p++) {
                if(players[p].active && 
                   abs(enemies[i].x-players[p].x) <= 1 && 
                   abs(enemies[i].y-players[p].y) <= 1) {
                    players[p].hp -= 10;
                    if(players[p].hp <= 0) {
                        if(--players[p].lives <= 0) players[p].active = false;
                        else players[p].hp = 100;
                    }
                }
            }
        }
    }

    // BOSS逻辑
    if(boss.active && --boss.attackTimer <= 0) {
        boss.attackTimer = 30 - boss.phase*5;
        if(boss.hp < boss.maxHp/2) boss.phase = 1;
        if(boss.hp < boss.maxHp/4) boss.phase = 2;

        if(boss.phase == 0 && rand()%3 == 0) {
            if(boss.x < players[0].x) boss.x++;
            else if(boss.x > players[0].x) boss.x--;
        }

        if(boss.phase == 1 && rand()%4 == 0) {
            int mx = boss.x + rand()%5 - 2;
            int my = boss.y + rand()%5 - 2;
            if(mx > 0 && my > 0 && mx < MAP_WIDTH-1 && my < MAP_HEIGHT-1
               && map[my][mx] == ' ') {
                boss.minions.push_back(make_pair(mx, my));
            }
        }
    }

    // 子弹逻辑
    for(int i = 0; i < MAX_BULLETS; i++) {
        if(bullets[i].active) {
            int nx = bullets[i].x + bullets[i].dx;
            int ny = bullets[i].y + bullets[i].dy;

            if(nx <= 0 || ny <= 0 || nx >= MAP_WIDTH-1 || ny >= MAP_HEIGHT-1
               || map[ny][nx] == '#') {
                bullets[i].active = false;
                continue;
            }

            bullets[i].x = nx;
            bullets[i].y = ny;

            for(int p = 0; p < playerCount; p++) {
                if(players[p].active && p != bullets[i].owner
                   && nx == players[p].x && ny == players[p].y) {
                    players[p].hp -= 20;
                    bullets[i].active = false;
                    if(players[p].hp <= 0) {
                        if(--players[p].lives <= 0) players[p].active = false;
                        else players[p].hp = 100;
                    }
                }
            }

            if(boss.active && bullets[i].owner >= 0 
               && nx == boss.x && ny == boss.y) {
                boss.hp -= 15;
                bullets[i].active = false;
                if(boss.hp <= 0) {
                    boss.active = false;
                    for(int p = 0; p < playerCount; p++) 
                        players[p].score += 100;
                }
            }
        }
    }
}

// 绘制游戏
void drawGame() {
    system("cls");
    for(int y = 0; y < MAP_HEIGHT; y++) {
        for(int x = 0; x < MAP_WIDTH; x++) {
            HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
            bool drawn = false;

            for(int p = 0; p < playerCount; p++) {
                if(players[p].active && x == players[p].x && y == players[p].y) {
                    SetConsoleTextAttribute(h, players[p].color);
                    cout << players[p].dir;
                    drawn = true;
                    break;
                }
            }

            if(!drawn && boss.active && x == boss.x && y == boss.y) {
                SetConsoleTextAttribute(h, 12);
                cout << 'B';
                drawn = true;
            }

            if(!drawn) {
                for(int i = 0; i < MAX_ENEMIES; i++) {
                    if(enemies[i].active && x == enemies[i].x && y == enemies[i].y) {
                        SetConsoleTextAttribute(h, 12);
                        cout << 'E';
                        drawn = true;
                        break;
                    }
                }
            }

            if(!drawn && boss.active) {
                for(int i = 0; i < (int)boss.minions.size(); i++) {
                    if(x == boss.minions[i].first && y == boss.minions[i].second) {
                        SetConsoleTextAttribute(h, 13);
                        cout << 'S';
                        drawn = true;
                        break;
                    }
                }
            }

            if(!drawn) {
                for(int i = 0; i < MAX_BULLETS; i++) {
                    if(bullets[i].active && x == bullets[i].x && y == bullets[i].y) {
                        SetConsoleTextAttribute(h, 14);
                        cout << '*';
                        drawn = true;
                        break;
                    }
                }
            }

            if(!drawn) {
                if(map[y][x] == '#') {
                    SetConsoleTextAttribute(h, 8);
                    cout << '#';
                } else {
                    cout << ' ';
                }
            }
        }
        cout << endl;
    }

    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
    for(int p = 0; p < playerCount; p++) {
        if(players[p].active) {
            cout << "P" << p+1 << ": HP=" << players[p].hp 
                 << " Lives=" << players[p].lives 
                 << " Score=" << players[p].score << "  ";
        }
    }
    if(boss.active) {
        cout << "\nBOSS HP: " << boss.hp << "/" << boss.maxHp 
             << " Phase: " << boss.phase+1;
    }
    cout << "\nControls: 1-WASD 2-TFGH 3-IJKL 4-ARROWS | Space-Shoot | Q-Weapon";
}

// 主函数
int main() {
    srand((unsigned)time(NULL));
    cout << "Players (1-4): ";
    cin >> playerCount;
    if(playerCount < 1 || playerCount > 4) playerCount = 1;

    initPlayers(playerCount);
    generateMaze();
    for(int i = 0; i < 3; i++) spawnEnemy();

    while(gameRunning) {
        if(kbhit()) {
            int key = getch();
            if(key == 224) { // 方向键
                key = getch();
                for(int p = 0; p < playerCount; p++) {
                    if(players[p].controls == ARROWS && players[p].active) {
                        switch(key) {
                            case 72: players[p].dir = '^'; break;
                            case 80: players[p].dir = 'v'; break;
                            case 75: players[p].dir = '<'; break;
                            case 77: players[p].dir = '>'; break;
                        }
                    }
                }
            } else {
                for(int p = 0; p < playerCount; p++) {
                    if(!players[p].active) continue;
                    switch(players[p].controls) {
                        case WASD:
                            if(key == 'w') { int ny = players[p].y-1; if(ny > 0 && map[ny][players[p].x]==' ') {players[p].y--; players[p].dir='^';} }
                            else if(key == 's') { int ny = players[p].y+1; if(ny < MAP_HEIGHT-1 && map[ny][players[p].x]==' ') {players[p].y++; players[p].dir='v';} }
                            else if(key == 'a') { int nx = players[p].x-1; if(nx > 0 && map[players[p].y][nx]==' ') {players[p].x--; players[p].dir='<';} }
                            else if(key == 'd') { int nx = players[p].x+1; if(nx < MAP_WIDTH-1 && map[players[p].y][nx]==' ') {players[p].x++; players[p].dir='>';} }
                            break;
                        case TFGH:
                            if(key == 't') { int ny = players[p].y-1; if(ny > 0 && map[ny][players[p].x]==' ') {players[p].y--; players[p].dir='^';} }
                            else if(key == 'g') { int ny = players[p].y+1; if(ny < MAP_HEIGHT-1 && map[ny][players[p].x]==' ') {players[p].y++; players[p].dir='v';} }
                            else if(key == 'f') { int nx = players[p].x-1; if(nx > 0 && map[players[p].y][nx]==' ') {players[p].x--; players[p].dir='<';} }
                            else if(key == 'h') { int nx = players[p].x+1; if(nx < MAP_WIDTH-1 && map[players[p].y][nx]==' ') {players[p].x++; players[p].dir='>';} }
                            break;
                        case IJKL:
                            if(key == 'i') { int ny = players[p].y-1; if(ny > 0 && map[ny][players[p].x]==' ') {players[p].y--; players[p].dir='^';} }
                            else if(key == 'k') { int ny = players[p].y+1; if(ny < MAP_HEIGHT-1 && map[ny][players[p].x]==' ') {players[p].y++; players[p].dir='v';} }
                            else if(key == 'j') { int nx = players[p].x-1; if(nx > 0 && map[players[p].y][nx]==' ') {players[p].x--; players[p].dir='<';} }
                            else if(key == 'l') { int nx = players[p].x+1; if(nx < MAP_WIDTH-1 && map[players[p].y][nx]==' ') {players[p].x++; players[p].dir='>';} }
                            break;
                        default: break;
                    }
                }
                if(key == ' ') {
                    for(int p = 0; p < playerCount; p++) 
                        if(players[p].active) shoot(p);
                } else if(key == 'q' || key == 'Q') {
                    for(int p = 0; p < playerCount; p++) {
                        if(players[p].active) {
                            do {
                                players[p].weapon = (players[p].weapon+1) % 3;
                            } while(players[p].weapon != 0 && players[p].ammo[players[p].weapon] <= 0);
                        }
                    }
                }
            }
        }

        updateGame();
        drawGame();
        Sleep(100);

        // 随机刷怪
        int activeEnemies = 0;
        for(int i = 0; i < MAX_ENEMIES; i++) 
            if(enemies[i].active) activeEnemies++;
        if(activeEnemies < 3 && rand() % 30 == 0) 
            spawnEnemy();

        // BOSS触发
        if(!boss.active && players[0].score > 50*level*level) {
            spawnBoss();
            level++;
        }

        // 胜负判断
        bool alive = false;
        for(int p = 0; p < playerCount; p++) 
            if(players[p].active) alive = true;
        if(!alive) gameRunning = false;
    }

    cout << "\nGAME OVER! Scores:\n";
    for(int p = 0; p < playerCount; p++) 
        cout << "P" << p+1 << ": " << players[p].score << endl;
    cout << "Press any key...";
    getch();
    return 0;
}