zoukankan      html  css  js  c++  java
  • 自制游戏Zombie代码

    /*
    ID: lightmain
    TASK: Zombie V4.3
    LANG: C++
    DATE: 20200920 22:00:02
    *///using CRLF, UTF-8
    
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <windows.h>
    #include <ctime>
    #include <fstream>
    #include <string>
    #include <conio.h>
    #include <cmath>
    #include <winuser.h>
    #include <list>
    #define pr printf
    #define F(i, j, k) for(register int i = j, kkllkl = k; i <= kkllkl; ++i)
    #define G(i, j, k) for(register int i = j, kkllkl = k; i >= kkllkl; --i)
    #define clr(a, v) memset((a), v, sizeof(a))
    #define sqr(x) ((x) * (x))
    using namespace std;
    typedef long long ll;
    
    #define chkmin(x, y) ((x) = ((x) < (y) ? (x) : (y)))
    #define chkmax(x, y) ((x) = ((x) < (y) ? (y) : (x)))
    
    // #define DEBUG
    
    /* --------------------------CSYZ1921------------------------- */
    class SCREEN;
    class CROOD;
    class PLAYER;
    class BULLET;
    class ENEMY;
    class ITEM;
    class BIRTH;
    class DIE;
    class GAME;
    
    /*
     * 屏幕的直接控制。
     * 横纵坐标以命令行坐标为准,与数组不同。
     * 注意:命令行坐标从0开始。 
    */
    class SCREEN {
    private:
        void HideCursor()//隐藏光标 
        {
            CONSOLE_CURSOR_INFO cursor_info = {1, 0}; 
            SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
        }
    
    public:
        static const int OUTPUT_WIDTH = 80, OUTPUT_HEIGHT = 45;
        static const int CHAR_WIDTH = 7, CHAR_HEIGHT = 16;
        int pressed[130];
    
        void set_cursor(int x, int y)
        {
            HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
            COORD pos={0,0};
            pos.X=x;
            pos.Y=y;
            SetConsoleCursorPosition(hOut,pos);
        }
    
        void init() {
            system("cls");
            clr(pressed, 0);
            HideCursor();
        }
    
        // 用字符c填满一个矩形
        void fill(char c, int x1, int y1, int x2, int y2) {
            F(i, y1, y2) {
                set_cursor(x1,i);
                F(j, x1, x2)
                    pr("%c",c);
            }
        }
    
        // 输出一个二维数组 下标从1开始
        void putarray(char **a, int wid, int hei, int x0, int y0) {
            F(i, 1, hei) {
                set_cursor(x0, y0 + i - 1);
                F(j, 1, wid)
                    pr("%c", a[i][j]);
            }
        }
    
        // 输出一个一维字符串 下标从0开始
        void putarray(char *a, int wid, int hei, int x0, int y0) {
            F(i, 1, hei) {
                set_cursor(x0, y0 + i - 1);
                F(j, 1, wid)
                    pr("%c", a[(i - 1) * wid + (j - 1)]);
            }
        }
    
        // 输出一个一维常量字符串
        void putarray(const char *a, int wid, int hei, int x0, int y0) {
            F(i, 1, hei) {
                set_cursor(x0, y0 + i - 1);
                F(j, 1, wid)
                    pr("%c", a[(i - 1) * wid + (j - 1)]);
            }
        }
    
        // 画一个框框,并把中间清空
        void draw_square(int x1, int y1, int x2, int y2) {
            F(y, y1, y2) {
                set_cursor(x1, y);
                F(x, x1, x2) {
                    char c = ' ';
                    if(x == x1 || x == x2) c = '|';
                    if(y == y1 || y == y2) c = '-';
                    pr("%c", c);
                }
            }
        }
    
        void putc(char c, int x, int y)
        {
            set_cursor(x,y);
            printf("%c",c);
        }
    
        // 检查按键c是否被按下
        bool check(char c) {
            return (GetKeyState(c) & 0x80) ? true : false;
        }
    
        bool changed(char c) {
            int x = GetKeyState(c) & 0x01;
            return (x != pressed[c]) ? (pressed[c] = x, true) : false;
        }
    
        bool click(char c) {
            return changed(c) && check(c);
        }
    } screen;
    
    /*
     * 实数坐标,(x, y)意义与数组坐标一致
    */
    const double eps = 1e-5;
    class crood {
      private:
        double x, y;
      public:
        crood(double x = 0.0, double y = 0.0): x(x), y(y) {}
        crood(int ix, int iy) {
            x = (double)ix; 
            y = (double)iy;
        }
    
        friend double dis(crood a, crood b);
        double get_len() {
            return sqrt(sqr(x) + sqr(y));
        }
        double get_x() { return x; }
        double get_y() { return y; }
    
        crood operator + (const crood &b) const {
            return crood(x + b.x, y + b.y);
        }
        crood operator - (const crood &b) const {
            return crood(x - b.x, y - b.y);
        }
        crood operator * (const double &q) const {
            return crood(x * q, y * q);
        }
        crood operator * (const int &q) const {
            return crood(x * q, y * q);
        }
        crood operator += (const crood &b) {
            x += b.x; y += b.y;
            return *this;
        }
        crood operator -= (const crood &b) {
            x -= b.x; y -= b.y;
            return *this;
        }
        crood operator *= (const double &q) {
            x *= q; y *= q;
            return *this;
        }
        void set_len(double length) {
            double old = get_len();
            if(old < eps) return ;
            x *= length / old;
            y *= length / old;
        }
        void set_x(double p) { x = p; }
        void set_y(double p) { y = p; }
        void set_dir(double ang) {
            double l = get_len();
            (*this) = crood(-sin(ang) * l, cos(ang) * l);
        }
        // 顺时针旋转,因为坐标系是左手系
        void turn_dir(double ang) {
            double px = x, py = y;
            x = cos(ang) * px - sin(ang) * py;
            y = cos(ang) * py + sin(ang) * px;
        }
    };
    
    /*
     * 公用的工具
    */
    
    const int WIDTH = (SCREEN :: OUTPUT_WIDTH) * (SCREEN :: CHAR_WIDTH), HEIGHT = (SCREEN :: OUTPUT_HEIGHT) * (SCREEN :: CHAR_HEIGHT);
    const int LEFT = 0, RIGHT = 1, UP = 2, DOWN = 3, LU = 4, LD = 5, RU = 6, RD = 7, NON = 8;
    const int dx[9] = {0, 0, -1, 1, -1, 1, -1, 1, 0}, dy[9] = {-1, 1, 0, 0, -1, -1, 1, 1, 0};
    const double PI = acos(-1);
    const int INF = 0x1f3f3f3f;
    FILE *debug;
    
    // 求实数绝对值
    inline double fabs(double x) { return x < 0 ? -x : x; }
    
    // 该坐标是否已出界
    int gout(crood v) {
        int ret = 0;
        if(v.get_x() < SCREEN :: CHAR_HEIGHT * 0.6 || v.get_x() > HEIGHT + SCREEN :: CHAR_HEIGHT * 0.4) ret |= 2;
        if(v.get_y() < SCREEN :: CHAR_WIDTH  * 0.6 || v.get_y() > WIDTH  + SCREEN :: CHAR_WIDTH * 0.4)  ret |= 1;
        return ret;
    }
    
    // 求向量(x, y)的旋转角
    double angle(crood v) {
        double x = v.get_x(), y = v.get_y();
        swap(y, x); y = -y;
        if(fabs(x) < eps) 
            if(fabs(y) > eps) return y > 0 ? PI / 2 : PI * 3 / 2;
            else return 0.0;
        double k = ((double)y) / ((double)x);
        double may = atan(k);
        if(x < 0) may += PI;
        if(may < 0) may += 2.0 * PI;
        // pr("(%.1lf, %.1lf) angle = %.2lf
    ", x, y, may / (PI * 2) * 360.0);
        return may;
    }
    
    // 求某旋转角对应的单位向量,向量的坐标系是数组坐标系
    crood vec(double ang) {
        return crood(-sin(ang), cos(ang));
    }
    
    // 求两个点之间的直线距离
    double dis(crood a, crood b) {
        return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
    }
    
    // 生成一个大整数,范围为[0, 0x3fffffff]
    int bigrand() {
        return (rand() << 15) + rand();
    }
    
    // 随机生成一个范围内的整数
    int randin(int l, int r) {
        return bigrand() % (r - l + 1) + l;
    }
    
    // 生成一个范围内的实数
    double drandin(double l, double r) {
        if(fabs(l - r) < eps) return l;
        if(r < l) return 0.0;
        return randin(0, 1000) * 1.0 * (r - l) / 1000.0 + l;
    }
    
    // 随机生成一个屏幕范围内的坐标
    crood randcrood() {
        double x = drandin(SCREEN :: CHAR_HEIGHT * 0.65, HEIGHT + SCREEN :: CHAR_HEIGHT * 0.35);
        double y = drandin(SCREEN :: CHAR_WIDTH * 0.65, WIDTH + SCREEN :: CHAR_WIDTH * 0.35);
        return crood(x, y);
    }
    
    // 四舍五入
    void toint(crood v, int &x, int &y) {
        x = ((int)(v.get_x() + 0.5));
        y = ((int)(v.get_y() + 0.5));
    }
    
    // 四舍五入
    int toint(double x) {
        return (int)(x + 0.5);
    }
    
    /*
     * 玩家的数据控制
    */
    class PLAYER {
      public:
        static const int BUFF_TYPES = 2;
        enum Skill {
            Grenade_rain, Belief_of_FFF
        };
      private:
        static const double MAXSPEED;
        static const double RADIUS;
        static const int REHEALTH[2], REHEALTH_COOLDOWN;
        static const int HEALTH;
        static const double ACCELERATION, INITIAL_SPEED;
        int HP, dir, lst_move_clock, lst_rehealth_clock, lst_accelerate_clock;
        int buff[BUFF_TYPES]; // 表示buff终结的时间
        crood pos, velo, tarvelo;
        double maxspeed;
      public:
        static const char MRK = '@';
        PLAYER() {}
    
        void init() {
            HP = HEALTH;
            pos = crood(HEIGHT / 2, WIDTH / 2);
            velo = crood(0, 0);
            maxspeed = MAXSPEED;
            lst_move_clock = lst_rehealth_clock = lst_accelerate_clock = clock();
            clr(buff, 0);
        }
    
        void move() {
            int c = clock();
            int t = c - lst_move_clock;
            lst_move_clock = c;
    
            int ret = gout(pos + velo * t);
            crood d = velo * t;
            if(ret & 2) { d.set_x(0.0); velo.set_x(0.0); }
            if(ret & 1) { d.set_y(0.0); velo.set_y(0.0); } 
            pos += d;
        }
        void accelerate() {
            int c = clock();
            crood deltav = tarvelo - velo;
            double deltaspeed = ACCELERATION * (c - lst_accelerate_clock);
            lst_accelerate_clock = c;
            if(deltav.get_len() > deltaspeed) deltav.set_len(deltaspeed);
            velo += deltav;
        }
        void set_dir(int x) {
            dir = x;
            tarvelo = crood(dx[dir], dy[dir]);
            tarvelo.set_len(maxspeed);
        } 
    
        void set_pos(double px, double py) { pos = crood(px, py); }
        void give_damage(int x, crood knockback) {
            HP = min(max(0, HP - x), HEALTH);
            velo += knockback;
        }
        void rehealth() {
            int c = clock();
            if(c - lst_rehealth_clock < REHEALTH_COOLDOWN) return ;
            lst_rehealth_clock = c;
            HP = min(HEALTH, HP + REHEALTH[dir == NON]); 
        }
        void reclock() {
            lst_move_clock = lst_rehealth_clock = lst_accelerate_clock = clock();
        }
        void give_buff(enum Skill type, int t) {
            buff[type] = clock() + t;
        }
    
        void frame_operate() {
            rehealth();
            accelerate();
            move();
        }
    
        double get_radius() { return RADIUS; }
        crood get_pos() { return pos; }
        int get_HP() { return HP; }
        int get_dir() { return dir; }
        crood get_v() { return velo; }
        double get_HPproportion() { return max(0.0, HP * 1.0 / HEALTH); }
        int get_buff(int type) { return buff[type] >= clock(); }
    } player;
    
    const double PLAYER :: MAXSPEED          = 0.17;
    const double PLAYER :: RADIUS            = 5;
    const int    PLAYER :: HEALTH            = 1000;
    const int    PLAYER :: REHEALTH[2]       = {5, 20};
    const int    PLAYER :: REHEALTH_COOLDOWN = 1700;
    const double PLAYER :: ACCELERATION      = 0.0005;
    const double PLAYER :: INITIAL_SPEED     = 0;
    
    /*
     * 射弹的数据控制
    */
    class BULLET {
      public:
        enum Type {
            normal, shock_wave, RPG, RPGwave, Fire
        };
        static const int TOTAL_TYPES = 5;
        static int lst_birth_clock[TOTAL_TYPES];
        static const int COOLDOWN[TOTAL_TYPES];
        static const double DEFLECTION[TOTAL_TYPES];
        static const double MOVING_DEFLECTION[TOTAL_TYPES];
      private:
        static const int IMMUNE[TOTAL_TYPES];
        static const char MRK[TOTAL_TYPES];
        static const int TIME_LIFE[TOTAL_TYPES];
        static const int PENETRATE[TOTAL_TYPES];
        static const int DEAD_SECONDARY[TOTAL_TYPES];
        static const int DAMAGE[TOTAL_TYPES];
        static const double MAXSPEED[TOTAL_TYPES];
        static const double RADIUS[TOTAL_TYPES];
        static const double ACCELERATION[TOTAL_TYPES];
        static const double INITIAL_SPEED[TOTAL_TYPES];
        static const double KNOCKBACK[TOTAL_TYPES];
        enum Type type;
        int damage, birth_clock, penetrate, lst_move_clock, time_life, lst_accelerate_clock;
        crood pos, velo, tarvelo;
        double radius, maxspeed;
        char mrk;
      public:
        BULLET(int ptype, crood ppos = crood(0, 0), crood towards = crood(1, 0)) {
            type = (enum Type)ptype;
            pos = ppos;
            damage = DAMAGE[type];
            tarvelo = towards;
            tarvelo.set_len(maxspeed = MAXSPEED[type]);
            velo = towards;
            velo.set_len(INITIAL_SPEED[type]);
            radius = RADIUS[type];
            time_life = TIME_LIFE[type] * drandin(0.65, 1.5);
            if(type == Fire && player.get_buff(PLAYER :: Belief_of_FFF)) { time_life = INF; damage *= 10; }
            mrk = MRK[type];
            birth_clock = lst_move_clock = lst_accelerate_clock = clock();
            penetrate = PENETRATE[type];
        }
    
        void move() {
            int c = clock();
            int t = c - lst_move_clock;
            lst_move_clock = c;
            pos += velo * t;
        }
        void accelerate() {
            int c = clock();
            crood deltav = tarvelo - velo;
            double deltaspeed = ACCELERATION[type] * (c - lst_accelerate_clock);
            lst_accelerate_clock = c;
            if(deltav.get_len() > deltaspeed) deltav.set_len(deltaspeed);
            velo += deltav;
        }
        void reclock() { lst_move_clock = lst_accelerate_clock = clock(); }
        void frame_operate() {
            accelerate();
            move();
        }
    
        double get_radius() { return radius; }
        crood get_pos() { return pos; }
        int get_damage() { --penetrate; return damage; }
        bool get_die() { return gout(pos) || (clock() - birth_clock > time_life) || (penetrate == 0); }
        char get_mrk() { return mrk; }
        int get_dead_secondary() { return DEAD_SECONDARY[type]; } 
        int get_type() { return type; }
        int get_immune() { return IMMUNE[type]; }
        crood get_knockback() { return tarvelo * KNOCKBACK[type];  }
        static int get_cooldown(int ptype) {
            if(ptype == RPG && player.get_buff(PLAYER :: Grenade_rain)) return COOLDOWN[RPG] / 20;
            return COOLDOWN[ptype]; 
        }
    };
    list<BULLET> bullets;
    typedef list<BULLET> :: iterator Buit;
    
    // normal = 0, shock_wave = 1, RPG = 2, RPGwave = 3, Fire = 4;
    const int    BULLET :: DAMAGE[BULLET :: TOTAL_TYPES]            = {400, 15000, 30000, 20, 300};
    const double BULLET :: MAXSPEED[BULLET :: TOTAL_TYPES]          = {0.4, 0.3, 0.7, 0.08, 0.4};
    const double BULLET :: ACCELERATION[BULLET :: TOTAL_TYPES]      = {0.0, 0.0, 0.0, 0.0, 0.0};
    const double BULLET :: INITIAL_SPEED[BULLET :: TOTAL_TYPES]     = {0.4, 0.3, 0.7, 0.08, 0.4};
    const double BULLET :: KNOCKBACK[BULLET :: TOTAL_TYPES]         = {0.2, 4.2, 0.0, 0.1, 0};
    const double BULLET :: RADIUS[BULLET :: TOTAL_TYPES]            = {3, 6, 5, 10, 10};
    int          BULLET :: lst_birth_clock[BULLET :: TOTAL_TYPES]   = {0, 0, 0, 0, 0};
    const int    BULLET :: COOLDOWN[BULLET :: TOTAL_TYPES]          = {34, 0, 3000, 0, 9};
    const double BULLET :: DEFLECTION[BULLET :: TOTAL_TYPES]        = {PI / 360, 0, PI / 360, 0, PI / 10};
    const double BULLET :: MOVING_DEFLECTION[BULLET :: TOTAL_TYPES] = {PI / 72, 0, PI / 360, 0, PI / 4};
    const int    BULLET :: DEAD_SECONDARY[BULLET :: TOTAL_TYPES]         = {-1, -1, BULLET :: RPGwave, -1, -1};
    const int    BULLET :: TIME_LIFE[BULLET :: TOTAL_TYPES]         = {INF, INF, INF, 400, 500};
    const int    BULLET :: PENETRATE[BULLET :: TOTAL_TYPES]         = {1, -1, 1, -1, -1};
    const int    BULLET :: IMMUNE[BULLET :: TOTAL_TYPES]            = {0, 10, 0, 0, 10};
    const char   BULLET :: MRK[BULLET :: TOTAL_TYPES]               = {'*', 'S', '%', '+', 'F'};
    
    /*
     * 敌怪的数据控制
    */
    class ENEMY {
      public:
        enum Type {
            Cole, Bob, Shooter, Shooter_bullet, Artillery, Artillery_bullet, Artillery_dead
        };
        static const int TOTAL_TYPES = 7;
        static const int PROBABILITY[TOTAL_TYPES];
        static const int CAPACITY[TOTAL_TYPES];
        static const int MAX_TYPE_CNT[TOTAL_TYPES];
        static int type_cnt[TOTAL_TYPES];
        enum MOVEAI {
            Warrior, Bullet_enemy, Range
        };
      private:
        static const int MOVEAI[TOTAL_TYPES];
        static const bool MULTIPIXEL[TOTAL_TYPES];
        static const int SECONDARY[TOTAL_TYPES];
        static const int DEAD_SECONDARY[TOTAL_TYPES];
        static const int SECONDARY_COOLDOWN[TOTAL_TYPES];
        static const int SCORE[TOTAL_TYPES];
        static const double MAXSPEED[TOTAL_TYPES];
        static const double RADIUS[TOTAL_TYPES];
        static const int DAMAGE[TOTAL_TYPES];
        static const int HEALTH[TOTAL_TYPES];
        static const char MRK[TOTAL_TYPES];
        static const int COOLDOWN[TOTAL_TYPES];
        static const int TIME_LIFE[TOTAL_TYPES];
        static const int PENETRATE[TOTAL_TYPES];
        static const double ACCELERATION[TOTAL_TYPES];
        static const double INITIAL_SPEED[TOTAL_TYPES];
        static const double KNOCKBACK[TOTAL_TYPES];
        static const double KNOCKBACK_IMMUNITY[TOTAL_TYPES];
        enum Type type;
        int HP, damage, score, randval, timelife;
        int lst_attack_clock, lst_move_clock, birth_clock, lst_secondary_clock, lst_accelerate_clock, lst_knockback_clock;
        int penetrate, immune;
        crood pos, velo, tarvelo;
        double maxspeed;
      public:
        ENEMY(int ptype, crood ppos, double tar = 0) {
            type = (enum Type)ptype;
            HP = HEALTH[type];
            pos = ppos;
            damage = DAMAGE[type];
            maxspeed = MAXSPEED[type];
            score = SCORE[type];
            if(TIME_LIFE[type] < INF) { timelife = TIME_LIFE[type] * drandin(0.65, 1.5); }
            else timelife = INF;
            birth_clock = lst_attack_clock = lst_move_clock = lst_secondary_clock = lst_accelerate_clock = lst_knockback_clock = clock();
            penetrate = PENETRATE[type];
            if(MOVEAI[type] == Bullet_enemy) {
                tarvelo = vec(tar);
                tarvelo.set_len(maxspeed);
                velo = tarvelo;
            }
            velo.set_len(INITIAL_SPEED[type]);
            randval = randin(1, 10000);
            immune = 0;
        }
    
        void move_enemy() {
            int c = clock();
            int t = c - lst_move_clock;
            lst_move_clock = c;
    
            int ret = gout(pos + velo * t);
            crood d = velo * t;
            if(ret & 2) { d.set_x(0.0); velo.set_x(0.0); }
            if(ret & 1) { d.set_y(0.0); velo.set_y(0.0); } 
            pos += d;
        }
        
        void move_bullet_enemy() {
            int c = clock();
            int t = c - lst_move_clock;
            lst_move_clock = c;
            pos += velo * t;
        }
    
        void move() {
            switch(MOVEAI[type]) {
                case Warrior: 
                case Range: { move_enemy(); break; }
                case Bullet_enemy: { move_bullet_enemy(); break; }
            }
        }
    
        void get_tarvelo_warrior() {
            tarvelo = player.get_pos() - pos;
            tarvelo.set_len(min(maxspeed, dis(player.get_pos(), pos)));
        }
    
        void get_tarvelo_range() {
            tarvelo = player.get_pos() - pos;
            tarvelo.set_len(maxspeed);
            tarvelo.turn_dir(((randval & 1) ? 1 : -1) * PI / 9 * 4);
        }
    
        void get_tarvelo() {
            switch(MOVEAI[type]) {
                case Warrior: { get_tarvelo_warrior(); break; }
                case Range: { get_tarvelo_range(); break; }
            }
        }
    
        void accelerate() {
            get_tarvelo();
            int c = clock();
            crood deltav = tarvelo - velo;
            double deltaspeed = ACCELERATION[type] * (c - lst_accelerate_clock);
            lst_accelerate_clock = c;
            if(deltav.get_len() > deltaspeed) deltav.set_len(deltaspeed);
            velo += deltav;
        }
    
        void give_damage(int x, int dim, crood knockback) { 
            if(immune != 0) return ;
            immune = dim;
            HP = max(0, HP - x);
            velo += knockback * (1.0 - KNOCKBACK_IMMUNITY[type]);
        }
        void frame_operate() {
            if(immune > 0) --immune;
            accelerate();
            move();
        }
        void reclock() { lst_secondary_clock = lst_move_clock = lst_attack_clock = lst_accelerate_clock = lst_knockback_clock = clock(); }
    
        int get_HP() { return HP; }
        double get_HPproportion() { return max(0.0, HP * 1.0 / HEALTH[type]); } 
        int get_damage() { 
            score = SCORE[type] * 2;
            int now_clock = clock();
            return (now_clock - lst_attack_clock >= COOLDOWN[type]) ? (lst_attack_clock = now_clock, --penetrate, damage) : 0; 
        }
        crood get_pos() { return pos; }
        double get_radius() { return RADIUS[type]; }
        char get_mrk() { return MRK[type]; }
        int get_score() { return score; }
        bool get_multipixel() { return MULTIPIXEL[type]; }
        int get_type() { return type; }
        bool get_die() { return HP <= 0 || gout(pos) || (clock() - birth_clock > timelife) || (penetrate == 0); }
        int get_secondray() {
            int c = clock();
            return (c - lst_secondary_clock >= SECONDARY_COOLDOWN[type]) ? (lst_secondary_clock = c, SECONDARY[type]) : -1;
        }
        crood get_knockback() {
            int c = clock();
            return (c - lst_attack_clock >= COOLDOWN[type]) ? (lst_attack_clock = c, tarvelo * KNOCKBACK[type]) : crood(0, 0); 
        }
        int get_dead_secondary() { return DEAD_SECONDARY[type]; }
    };
    list<ENEMY> enemies;
    typedef list<ENEMY> :: iterator Enit;
    
    // Cole = 0, Bob = 1, Shooter = 2, Shooter_bullet = 3, Artillery = 4, Artillery_bullet = 5, Artillery_dead = 6;
    const int    ENEMY :: HEALTH[ENEMY :: TOTAL_TYPES]              = {1000, 50000, 5000, 1, 350000, INF, INF};
    const int    ENEMY :: DAMAGE[ENEMY :: TOTAL_TYPES]              = {150, 50, 50, 200, 0, 500, 0};
    const double ENEMY :: MAXSPEED[ENEMY :: TOTAL_TYPES]            = {0.12, 0.04, 0.07, 0.3, 0, 0.35, 0.2};
    const double ENEMY :: ACCELERATION[ENEMY :: TOTAL_TYPES]        = {0.0003, 0.0002, 0.0003, 0, 0, 0, 0};
    const double ENEMY :: INITIAL_SPEED[ENEMY :: TOTAL_TYPES]       = {0.0, 0.0, 0.0,  0.3, 0, 0.35, 0.2};
    const double ENEMY :: KNOCKBACK[ENEMY :: TOTAL_TYPES]           = {0.2, 0.2, 0.2,  0.1, 0, 1.4, 0};
    const double ENEMY :: KNOCKBACK_IMMUNITY[ENEMY :: TOTAL_TYPES]  = {0,   0.93, 0.8,  0,   1, 1, 0};
    const double ENEMY :: RADIUS[ENEMY :: TOTAL_TYPES]              = {8, 12, 8, 2, 35, 8, -INF}; // 将半径设为-INF可以使之无法被接触
    const int    ENEMY :: TIME_LIFE[ENEMY :: TOTAL_TYPES]           = {INF, INF, INF, INF, INF, INF, 800};
    const int    ENEMY :: PENETRATE[ENEMY :: TOTAL_TYPES]           = {-1, -1, -1, 1, -1, 1, -1};
    const int    ENEMY :: COOLDOWN[ENEMY :: TOTAL_TYPES]            = {300, 300, 300, 0, 0, 0, 0};
    const int    ENEMY :: SECONDARY[ENEMY :: TOTAL_TYPES]           = {-1, -1, ENEMY :: Shooter_bullet, -1, ENEMY :: Artillery_bullet, -1, -1};
    const int    ENEMY :: DEAD_SECONDARY[ENEMY :: TOTAL_TYPES]      = {-1, -1, -1, -1, ENEMY :: Artillery_dead, -1, -1};
    const int    ENEMY :: SECONDARY_COOLDOWN[ENEMY :: TOTAL_TYPES]  = {0, 0, 2000, 0, 3000, 0, 0};
    const int    ENEMY :: MOVEAI[ENEMY :: TOTAL_TYPES]              = {ENEMY :: Warrior, ENEMY :: Warrior, ENEMY :: Range, ENEMY :: Bullet_enemy, ENEMY :: Warrior, ENEMY :: Bullet_enemy, ENEMY :: Bullet_enemy};
    const int    ENEMY :: CAPACITY[ENEMY :: TOTAL_TYPES]            = {10, 40, 20, 0, 200, 0, 0};
    const int    ENEMY :: MAX_TYPE_CNT[ENEMY :: TOTAL_TYPES]        = {INF, INF, INF, INF, 1, INF, INF};
    int          ENEMY :: type_cnt[ENEMY :: TOTAL_TYPES]            = {0};
    const int    ENEMY :: PROBABILITY[ENEMY :: TOTAL_TYPES]         = {8300, 800, 800, 0, 100, 0, 0}; // 万分数
    const char   ENEMY :: MRK[ENEMY :: TOTAL_TYPES]                 = {'X', 'O', 'B', '-', 'H', 'C', '+'};
    const bool   ENEMY :: MULTIPIXEL[ENEMY :: TOTAL_TYPES]          = {false, true, false, false, true, true, false};
    const int    ENEMY :: SCORE[ENEMY :: TOTAL_TYPES]               = {10, 85, 40, 0, 1000, 0, 0};
    
    /*
     * 物品的数据控制
    */
    class ITEM {
      public:
        enum Type {
            Recovery_potion
        };
        static const int TOTAL_TYPES = 2;
        static const int PROBABILITY[TOTAL_TYPES];
        static const int BIRTH_COOLDOWN;
        static int lst_birth_clock;
      private:
        static const char MRK[TOTAL_TYPES];
        static const int TIME_LIFE[TOTAL_TYPES];
        static const int PENETRATE[TOTAL_TYPES];
        static const double RADIUS[TOTAL_TYPES];
        enum Type type;
        int count, birth_clock;
        crood pos;
    
        void recovery_potion() {
            player.give_damage(-300, crood(0, 0));
        }
      public:
        ITEM(int ptype, crood ppos) {
            type = (enum Type)ptype;
            pos = ppos;
            birth_clock = clock();
            count = 0;
        }
    
        void operate() {
            switch(type) {
                case Recovery_potion: { recovery_potion(); break; }
            }
            ++count;
        }
    
        crood get_pos() { return pos; }
        char get_mrk() { return MRK[type]; }
        bool get_die() { return (clock() - birth_clock > TIME_LIFE[type]) || (count >= PENETRATE[type]); }
        double get_radius() { return RADIUS[type]; }
        int get_type() { return type; }
    };
    list<ITEM> items;
    typedef list<ITEM> :: iterator Itit;
    
    const int    ITEM :: PROBABILITY[ITEM :: TOTAL_TYPES] = {10000};
    const char   ITEM :: MRK[ITEM :: TOTAL_TYPES]         = {'R'};
    const int    ITEM :: TIME_LIFE[ITEM :: TOTAL_TYPES]   = {INF};
    const int    ITEM :: PENETRATE[ITEM :: TOTAL_TYPES]   = {1};
    const double ITEM :: RADIUS[ITEM :: TOTAL_TYPES]      = {6};
    const int    ITEM :: BIRTH_COOLDOWN                   = 60000;
    int          ITEM :: lst_birth_clock                  = 0;
    
    /*
     * 生成实体
    */
    int enemy_cnt, bullet_cnt, item_cnt, enemy_capacity;
    
    class BIRTH {
      private:
        static const int MAX_ENEMIES, MAX_BULLETS, MAX_ITEMS;
        static const double MIN_BIRTH_ENEMY_DISTANCE;
        static const double MIN_BIRTH_ITEM_DISTANCE;
      public:
        /********************** 射弹生成 **********************/
        // 生成在玩家位置的指定方向的射弹
        void birth_normal_bullet(int type, int dir) {
            #ifdef DEBUG
            fprintf(debug, "Trying to birth a bullet type = %d
    ", type);
            fflush(debug);
            #endif
            int now_clock = clock();
            if(now_clock - BULLET :: lst_birth_clock[type] < BULLET :: get_cooldown(type)) return ;
            if(bullet_cnt >= MAX_BULLETS) return ;
            BULLET :: lst_birth_clock[type] = now_clock;
    
            crood towards(dx[dir], dy[dir]);
            double ang = angle(towards);
            double deflection = (player.get_dir() == NON) ? BULLET :: DEFLECTION[type] : BULLET :: MOVING_DEFLECTION[type];
            ang += drandin(-deflection, deflection);
            towards = vec(ang);
    
            bullets.push_back(BULLET(type, player.get_pos(), towards));
            ++bullet_cnt;
        }
    
        // 生成在指定位置的指定方向的射弹
        void birth_pos_bullet(int type, crood pos, double ang) {
            bullets.push_back(BULLET(type, pos, vec(ang)));
            ++bullet_cnt;
        }
    
        void birth_shock_wave() {
            int now_clock = clock(), type = BULLET :: shock_wave;
            if(now_clock - BULLET :: lst_birth_clock[type] < BULLET :: COOLDOWN[type]) return ;
            BULLET :: lst_birth_clock[type] = now_clock;
    
            double ang0 = PI / 100, ang = 0;
            F(i, 1, 200) {
                if(bullet_cnt >= MAX_BULLETS) return ;
                bullets.push_back(BULLET(type, player.get_pos(), vec(ang)));
                ang += ang0;
                ++bullet_cnt;
            }
        }
    
        /********************** 敌怪生成 **********************/
        void birth_normal_enemy() {
            if(enemy_cnt >= MAX_ENEMIES) return ;
    
            crood pp = player.get_pos(), ep;
            ep = randcrood();
            if(dis(ep, pp) < MIN_BIRTH_ENEMY_DISTANCE) return ;
    
            int type = 0;
            int randval = randin(1, 10000), randl = 1, randr = 1;
            F(i, 0, ENEMY :: TOTAL_TYPES - 1) {
                randr += ENEMY :: PROBABILITY[i];
                if(randl <= randval && randval < randr)
                    { type = i; break; } 
                randl = randr;
            }
            if(ENEMY :: MAX_TYPE_CNT[type] <= ENEMY :: type_cnt[type]) return ;
    
            ++enemy_cnt;
            ++ENEMY :: type_cnt[type];
            enemy_capacity += ENEMY :: CAPACITY[type];
            enemies.push_back(ENEMY(type, ep));
        }
    
        void birth_bullet_enemy(int type, crood pos) {
            ++enemy_cnt;
            ++ENEMY :: type_cnt[type];
            double ang = angle(player.get_pos() - pos);
            enemies.push_back(ENEMY(type, pos, ang));
        }
    
        void birth_dead(int type, crood pos) {
            double ang0 = PI / 45, ang = 0;
            F(i, 1, 90) {
                ++enemy_cnt;
                ++ENEMY :: type_cnt[type];
                enemies.push_back(ENEMY(type, pos, ang));
                ang += ang0;
            }
    
        }
    
        void birth_enemy(int type = 0, crood pos = crood(0, 0)) {
            switch(type) {
                case ENEMY :: Cole:
                case ENEMY :: Bob:
                case ENEMY :: Shooter:
                case ENEMY :: Artillery:
                    { birth_normal_enemy(); break; }
                case ENEMY :: Shooter_bullet:
                case ENEMY :: Artillery_bullet:
                    { birth_bullet_enemy(type, pos); break; }
                case ENEMY :: Artillery_dead:
                    { birth_dead(type, pos); break; }
            }
        }
    
        /********************** 物品生成 **********************/
        void birth_random_item() {
            if(item_cnt >= MAX_ITEMS) return ;
            crood pp = player.get_pos(), ip;
            do {
                ip = randcrood();
            } while(dis(ip, pp) < MIN_BIRTH_ITEM_DISTANCE);
    
            int randval = randin(1, 10000), type = 0, randl = 1, randr = 1;
            F(i, 0, ITEM :: TOTAL_TYPES - 1) {
                randr += ITEM :: PROBABILITY[i];
                if(randl <= randval && randval < randr)
                    { type = i; break; } 
                randl = randr;
            }
    
            ++item_cnt;
            items.push_back(ITEM(type, ip));
        }
    
        static const int Random_item = 0;
        void birth_item(int command) {
            if(clock() - ITEM :: lst_birth_clock < ITEM :: BIRTH_COOLDOWN) return ;
            ITEM :: lst_birth_clock = clock();
            switch(command) {
                case Random_item: { birth_random_item(); break; }
            }
        }
    
        void birth_player() {
            player.init();
        }
    } birth;
    
    const int    BIRTH :: MAX_ENEMIES               = 1000;
    const int    BIRTH :: MAX_BULLETS               = 1000;
    const int    BIRTH :: MAX_ITEMS                 = 1000;
    const double BIRTH :: MIN_BIRTH_ENEMY_DISTANCE  = 100.0;
    const double BIRTH :: MIN_BIRTH_ITEM_DISTANCE   = 50.0;
    
    /*
     * 消灭实体
    */
    class DIE {
      private:
        void die_normal_enemy(Enit it) {
            --enemy_cnt;
            enemy_capacity -= ENEMY :: CAPACITY[it -> get_type()];
            --ENEMY :: type_cnt[it -> get_type()];
            enemies.erase(it);
        }
    
        void die_artillery(Enit it) {
            --enemy_cnt;
            enemy_capacity -= ENEMY :: CAPACITY[it -> get_type()];
            --ENEMY :: type_cnt[it -> get_type()];
            birth.birth_enemy(it -> get_dead_secondary(), it -> get_pos());
            enemies.erase(it);
        }
    
        void die_normal_bullet(Buit it) {
            --bullet_cnt;
            bullets.erase(it);
        }
    
        void die_normal_item(Itit it) {
            --item_cnt;
            items.erase(it);
        }
    
        void die_RPG(Buit b) {
            --bullet_cnt;
            double ang0 = PI / 20, ang = 0;
            F(i, 1, 40) { 
                birth.birth_pos_bullet(b -> get_dead_secondary(), b -> get_pos(), ang);
                ang += ang0;
            }
            bullets.erase(b);
        }
      public:
        void die_enemy(const Enit &e) {
            switch(e -> get_type()) {
                case ENEMY :: Cole:
                case ENEMY :: Bob:
                case ENEMY :: Shooter:
                case ENEMY :: Shooter_bullet:
                case ENEMY :: Artillery_bullet:
                case ENEMY :: Artillery_dead:
                    { die_normal_enemy(e); break; }
                case ENEMY :: Artillery:
                    { die_artillery(e); break; }
            }
        }
    
        void die_bullet(const Buit &b) {
            switch(b -> get_type()) {
                case BULLET :: normal: 
                case BULLET :: shock_wave: 
                case BULLET :: RPGwave:
                case BULLET :: Fire:
                    { die_normal_bullet(b); break; }
                case BULLET :: RPG:           
                    { die_RPG(b); break; }
            }
        }
    
        void die_item(const Itit &i) {
            switch(i -> get_type()) {
                case ITEM :: Recovery_potion:
                    { die_normal_item(i); break; }
            }
        }
    } die;
    
    /*
     * 游戏主体的初始化和运行
    */
    class GAME {
    private:
        static const int MAX_ENEMY_BIRTH_FREQUENCY, HALF_CAPACITY;
        static const int MIN_FRAME_DELAY;
        static const int ITEM_BIRTH_COOLDOWN;
        static const int WEAPON_CNT = 3;
        static const int WEAPONS[WEAPON_CNT];
        static const int sShock_wave = 0, sRage_potion = 1, sSWZH = 2;
        static const int SKILLS[WEAPON_CNT];
        static const int SKILL_COOLDOWN[WEAPON_CNT];
        static int lst_skill_clock[WEAPON_CNT];
        static const char *WEAPON_NAME[WEAPON_CNT];
        static const char *SKILL_NAME[WEAPON_CNT];
        char field[SCREEN :: OUTPUT_HEIGHT + 1][SCREEN :: OUTPUT_WIDTH + 1];
        char lst_field[SCREEN :: OUTPUT_HEIGHT + 1][SCREEN :: OUTPUT_WIDTH + 1];
        int score, frame_lived, game_start_clock, lst_birth_item_clock;
        double lst_attacked_enemy_HPproportion;
        int hand_weapon, lst_hand_weapon, delta_time, lst_clock;
    
        /**
         * 在field上画一个实心圆
        ***/
        void draw_circle(const Enit &e) {
            crood center = e -> get_pos();
            double radius = e -> get_radius();
            int l = toint((center.get_y() - radius) / SCREEN :: CHAR_WIDTH);
            int r = toint((center.get_y() + radius) / SCREEN :: CHAR_WIDTH);
            chkmax(l, 1); chkmin(r, SCREEN :: OUTPUT_WIDTH);
            F(i, l, r) {
                double len = sqrt(sqr(radius) - sqr(center.get_y() - i * SCREEN :: CHAR_WIDTH));
                int u = toint((center.get_x() - len) / SCREEN :: CHAR_HEIGHT);
                int d = toint((center.get_x() + len) / SCREEN :: CHAR_HEIGHT);
                chkmax(u, 1); chkmin(d, SCREEN :: OUTPUT_HEIGHT);
                F(j, u, d)
                    field[j][i] = e -> get_mrk();
            }
        }
    
        /**
         * 在field上画一个小的十字
        ***/
        void draw_cross(const Enit &e) {
            int x, y;
            crood p = e -> get_pos();
            p = crood(p.get_x() / SCREEN :: CHAR_HEIGHT, p.get_y() / SCREEN :: CHAR_WIDTH);
            toint(p, x, y);
            field[x][y] = e -> get_mrk();
            if(y < SCREEN :: OUTPUT_WIDTH) field[x][y + 1] = e -> get_mrk();
            if(y > 1) field[x][y - 1] = e -> get_mrk();
            if(x < SCREEN :: OUTPUT_HEIGHT) field[x + 1][y] = e -> get_mrk();
            if(x > 1) field[x - 1][y] = e -> get_mrk();
        }
    
        /**
         * 更新field
        ***/
        void update_field() {
            F(i, 1, SCREEN :: OUTPUT_HEIGHT) F(j, 1, SCREEN :: OUTPUT_WIDTH) {
                lst_field[i][j] = field[i][j];
                field[i][j] = ' ';
            }
            int x, y;
            crood p;
            for(Buit b = bullets.begin(); b != bullets.end(); ++b) {
                p = b -> get_pos();
                p = crood(p.get_x() / SCREEN :: CHAR_HEIGHT, p.get_y() / SCREEN :: CHAR_WIDTH);
                toint(p, x, y);
                field[x][y] = b -> get_mrk();
            }
            p = player.get_pos();
            p = crood(p.get_x() / SCREEN :: CHAR_HEIGHT, p.get_y() / SCREEN :: CHAR_WIDTH);
            toint(p, x, y);
            field[x][y] = PLAYER :: MRK;
            for(Enit e = enemies.begin(); e != enemies.end(); ++e) {
                if(e -> get_multipixel()) {
                    draw_circle(e);
                } else {
                    p = e -> get_pos();
                    p = crood(p.get_x() / SCREEN :: CHAR_HEIGHT, p.get_y() / SCREEN :: CHAR_WIDTH);
                    toint(p, x, y);
                    field[x][y] = e -> get_mrk();
                }
            }
            for(Itit i = items.begin(); i != items.end(); ++i) {
                p = i -> get_pos();
                p = crood(p.get_x() / SCREEN :: CHAR_HEIGHT, p.get_y() / SCREEN :: CHAR_WIDTH);
                toint(p, x, y);
                field[x][y] = i -> get_mrk();
            }
        }
    
        /**
         * 输出field
        ***/
        void print_field() {
            screen.set_cursor(0, 0);
            int now_clock = clock();
            int length = min(player.get_HPproportion() * 50 + 0.5, 50.5);
            pr("Player HP     ["); F(i, 1, length) pr("#"); F(i, 1, 50 - length) pr(" "); pr("] %.0lf%% [%d]   
    ", player.get_HPproportion() * 100, player.get_HP());
    
            int passed = now_clock - BULLET :: lst_birth_clock[WEAPONS[hand_weapon]], total = BULLET :: get_cooldown(WEAPONS[hand_weapon]);
            length = passed * 10 / total + 0.5;
            chkmin(length, 10);
            pr("%s [", WEAPON_NAME[hand_weapon]); F(i, 1, length) pr("#"); F(i, 1, 10 - length) pr(" "); pr("] %.1lf s      
    ", max(0.0, (total - passed) / 1000.0));
    
            passed = now_clock - lst_skill_clock[SKILLS[hand_weapon]], total = SKILL_COOLDOWN[SKILLS[hand_weapon]];
            length = passed * 30 / total + 0.5;
            chkmin(length, 30);
            pr("%s [", SKILL_NAME[hand_weapon]); F(i, 1, length) pr("#"); F(i, 1, 30 - length) pr(" "); pr("] %.1lf s      
    ", max(0.0, (total - passed) / 1000.0));
    
            length = lst_attacked_enemy_HPproportion * 30 + 0.5;
            pr("Enemy HP      ["); F(i, 1, length) pr("#"); F(i, 1, 30 - length) pr(" "); pr("] %.0lf%%      
    ", lst_attacked_enemy_HPproportion * 100);
    
            F(i, 1, SCREEN :: OUTPUT_HEIGHT) F(j, 1, SCREEN :: OUTPUT_WIDTH) {
                if(field[i][j] != lst_field[i][j])
                    screen.putc(field[i][j], j - 1, i - 1 + 4);
            }
    
            screen.set_cursor(0, SCREEN :: OUTPUT_HEIGHT + 4);
            crood v = player.get_pos();
            pr("
    Enemy count [%d] Bullet count [%d] Game time: %.1lf s Score: %d delta_time = %d|||", 
                enemy_cnt, 
                bullet_cnt,
                (now_clock - game_start_clock) / 1000.0,
                score,
                delta_time
            );
        }
    
        /**
         * 八向输入。
         * 按上下左右的顺序输入四个方向的对应按键符号,输出当前键盘状态所表示的对应八向方向。
        ***/
        int inputdir(char uper, char downer, char lefter, char righter) {
            bool a[4];
            a[0] = screen.check(uper);
            a[1] = screen.check(righter);
            a[2] = screen.check(downer);
            a[3] = screen.check(lefter);
            if(a[0] && a[2]) a[0] = a[2] = false;
            if(a[1] && a[3]) a[1] = a[3] = false;
            if(a[0] && a[1]) return RU; if(a[0] && a[3]) return LU; if(a[2] && a[1]) return RD; if(a[2] && a[3]) return LD;
            if(a[0]) return UP; if(a[1]) return RIGHT; if(a[2]) return DOWN; if(a[3]) return LEFT;
            return NON;
        }
    
        /**
         * 返回实际的敌人生成概率
        ***/
        int enemy_birth_frequency() {
            return MAX_ENEMY_BIRTH_FREQUENCY * HALF_CAPACITY / (enemy_capacity + HALF_CAPACITY);
        }
    
        /**
         * 切换武器
        ***/
        void shift_weapon(int tar = -1) {
            if(tar == -1) {
                lst_hand_weapon = hand_weapon++;
                if(hand_weapon >= WEAPON_CNT) hand_weapon = 0;
            } else if(tar == -2) {
                swap(hand_weapon, lst_hand_weapon);
            } else {
                if(lst_hand_weapon != hand_weapon) lst_hand_weapon = hand_weapon;
                hand_weapon = tar;
            }
        }
    
        /**
         * 暂停
        ***/
        void Pause() {
            screen.putarray("Paused", 6, 1, 38, 26);
            while(!screen.click('P')) { Sleep(10); }
            F(i, 39, 45)
                screen.putc(field[23][i], i - 1, 26);
        }
    
        /**
         * 在暂停之后调用:重置所有实体的clock。
        ***/
        void reclock() {
            int delta = clock() - lst_clock;
            for(Buit b = bullets.begin(); b != bullets.end(); ++b)
                b -> reclock();
            F(i, 0, BULLET :: TOTAL_TYPES - 1)
                BULLET :: lst_birth_clock[i] += delta;
            F(i, 0, WEAPON_CNT - 1)
                lst_skill_clock[i] += delta;
            game_start_clock += delta;
            for(Enit e = enemies.begin(); e != enemies.end(); ++e)
                e -> reclock();
            player.reclock();
            lst_clock = lst_birth_item_clock = clock();
        }
    
        /**
         * 释放技能
        ***/
        void release_skill(int type) {
            int c = clock();
            if(c - lst_skill_clock[type] < SKILL_COOLDOWN[type]) return ;
            lst_skill_clock[type] = c;
            switch(type) {
                case sShock_wave:  { birth.birth_shock_wave(); break; }
                case sRage_potion: { player.give_buff(PLAYER :: Grenade_rain, 1600); break; }
                case sSWZH:        { player.give_buff(PLAYER :: Belief_of_FFF, 2500); break; }
            }
        }
    
        /**
         * 实体更新
        ***/
        bool update_entity() {
            bool died[3] = {false, false, false};
            static const int Bu = 1, En = 0, It = 2;
    
            #ifdef DEBUG
            fprintf(debug, "Frame: %d
    ", frame_lived);
            fflush(debug);
            #endif
    
            // 游戏状态更新
            if(screen.click('Q')) { shift_weapon(-2); }
            if(screen.click(VK_SHIFT)) { shift_weapon(); }
            F(i, 0, WEAPON_CNT - 1) if(screen.click(i + 1 + '0'))
                { shift_weapon(i); }
            if(screen.click('P')) { Pause(); reclock(); return false; }
    
            // 实体独立状态更新
            player.set_dir(inputdir('W', 'S', 'A', 'D'));
            player.frame_operate();
            for(Enit e = enemies.begin(); e != enemies.end(); ++e)
                e -> frame_operate();
            for(Buit b = bullets.begin(); b != bullets.end(); ++b)
                b -> frame_operate();
            
            // 生成实体
            F(i, 1, delta_time) {           if(randin(1, 10000) <= enemy_birth_frequency())
                    birth.birth_enemy();
            }
            F(i, 1, max(delta_time / 3, 1)) {
                int bullet_dir = inputdir(VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT);
                if(bullet_dir != NON) birth.birth_normal_bullet(WEAPONS[hand_weapon], bullet_dir);
            }
            if(screen.check(VK_SPACE)) release_skill(SKILLS[hand_weapon]);
            birth.birth_item(BIRTH :: Random_item);
            
            for(Enit e = enemies.begin(); e != enemies.end(); ++e) {
                int se = e -> get_secondray();
                if(se >= 0) {
                    birth.birth_enemy(se, e -> get_pos());
                }
            }
    
            #ifdef DEBUG
            fprintf(debug, "Birth finished
    ");
            fflush(debug);
            #endif
            
            // 判断碰撞并消灭实体
            // 射弹的独立消灭
            for(Buit b = bullets.begin(); b != bullets.end(); died[Bu] ? (died[Bu] = false) : (++b, false))
                if(b -> get_die()) {
                    die.die_bullet(b++);
                    died[Bu] = true;
                }
            // 敌怪的独立消灭
            for(Enit e = enemies.begin(); e != enemies.end(); died[En] ? (died[En] = false) : (++e, false))
                if(e -> get_die()) {
                    die.die_enemy(e++);
                    died[En] = true;
                }
            // 射弹与敌怪
            for(Buit b = bullets.begin(); b != bullets.end(); died[Bu] ? (died[Bu] = false) : (++b, false))
                for(Enit e = enemies.begin(); e != enemies.end(); died[En] ? (died[En] = false) : (++e, false)) {
                    crood bp = b -> get_pos();
                    crood ep = e -> get_pos();
                    double expect_dis = b -> get_radius() + e -> get_radius();
    
                    bool died[2] = {false, false}; // ene, bul
                    if(dis(ep, bp) < expect_dis) {
                        e -> give_damage(b -> get_damage(), b -> get_immune(), b -> get_knockback());
                        lst_attacked_enemy_HPproportion = e -> get_HPproportion();
    
                        if(e -> get_die()) {
                            score += e -> get_score();
                            die.die_enemy(e++);
                            died[En] = true;
                        }
                        if(b -> get_die()) {
                            die.die_bullet(b++);
                            died[Bu] = true;
                        }
                    }
                }
            // 物品与玩家
            for(Itit i = items.begin(); i != items.end(); died[It] ? (died[It] = false) : (++i, false)) {
                crood ip = i -> get_pos();
                crood pp = player.get_pos();
                double expect_dis = player.get_radius() + i -> get_radius();
                if(dis(ip, pp) < expect_dis) {
                    i -> operate();
                    if(i -> get_die()) {
                        die.die_item(i++);
                        died[It] = true;
                    }
                }
            }
            // 敌怪与玩家
            bool Gamefail = false;
            for(Enit e = enemies.begin(); e != enemies.end(); died[En] ? (died[En] = false) : (++e, false)) {
                crood ep = e -> get_pos();
                crood pp = player.get_pos();
                double expect_dis = player.get_radius() + e -> get_radius();
                if(dis(ep, pp) < expect_dis) {
                    player.give_damage(e -> get_damage(), e -> get_knockback());
                    if(player.get_HP() <= 0)
                        Gamefail = true;
                    if(e -> get_die()) {
                        score += e -> get_score();
                        die.die_enemy(e++);
                        died[En] = true;
                    }
                }
            }
            #ifdef DEBUG            
            fprintf(debug, "Die finished
    ");
            fflush(debug);
            #endif
    
            return Gamefail;
        }
    
    public:
        /**
         * 初始化
        ***/
        void Init() {
            system("cls");
            F(i, 1, SCREEN :: OUTPUT_HEIGHT) F(j, 1, SCREEN :: OUTPUT_WIDTH)
                field[i][j] = lst_field[i][j] = ' ';
            enemy_cnt = bullet_cnt = item_cnt = frame_lived = score = enemy_capacity = 0;
            F(i, 0, ENEMY :: TOTAL_TYPES - 1)
                ENEMY :: type_cnt[i] = 0;
            hand_weapon = lst_hand_weapon = 0;
            lst_attacked_enemy_HPproportion = 0;
            enemies.clear();
            bullets.clear();
            items.clear();
            birth.birth_player();
            print_field();
    
            game_start_clock = clock();
            F(i, 0, BULLET :: TOTAL_TYPES - 1)
                BULLET :: lst_birth_clock[i] = game_start_clock;
            F(i, 0, WEAPON_CNT - 1)
                lst_skill_clock[i] = game_start_clock;
            lst_birth_item_clock = ITEM :: lst_birth_clock = game_start_clock;
        }
    
        /**
         * 游戏运行循环
        ***/
        void Rungame() {
            lst_clock = clock();
            while(true) {
                delta_time = clock() - lst_clock;
                if(delta_time < MIN_FRAME_DELAY) {
                    Sleep(MIN_FRAME_DELAY - delta_time);
                    delta_time = MIN_FRAME_DELAY;
                }
                lst_clock = clock();
                ++frame_lived;
                
                bool Gamefail = update_entity();
    
                // 输出
                update_field();
                print_field();
                if(Gamefail)
                    return ;
            }
        }
    
        /**
         * 游戏失败
        ***/
        void fail() {
            screen.draw_square(20, 15, 59, 34);
            screen.putarray("You failed!", 11, 1, 35, 18);
            char s[38];
            sprintf(s, "Score: %d", score);
            screen.set_cursor(25, 23); for(int i = 0; s[i] != ''; ++i) pr("%c", s[i]);
            int t = (clock() - game_start_clock) / 1000;
            if(t < 60) sprintf(s, "Time survived: %d sec", t);
            else sprintf(s, "Time survived: %d min %d sec", t / 60, t % 60);
            screen.set_cursor(25, 25); for(int i = 0; s[i] != ''; ++i) pr("%c", s[i]);
            screen.putarray("Press space bar to restart", 26, 1, 27, 30);
    
            while(!screen.check(VK_SPACE));
        }
    } Game;
    
    const int   GAME :: MIN_FRAME_DELAY                     = 3; // 最小帧间时间
    const int   GAME :: MAX_ENEMY_BIRTH_FREQUENCY           = 80; // 每毫秒生成敌人几率的万分比。10除以它,就是期望生成一个敌人的间隔秒数  默认为50 (0.2秒一个敌人)
    const int   GAME :: HALF_CAPACITY                       = 120; 
    const int   GAME :: WEAPONS[GAME :: WEAPON_CNT]         = {BULLET :: normal, BULLET :: RPG, BULLET :: Fire}; 
    const int   GAME :: SKILLS[GAME :: WEAPON_CNT]          = {GAME :: sShock_wave, GAME :: sRage_potion, GAME :: sSWZH}; 
    const int   GAME :: SKILL_COOLDOWN[GAME :: WEAPON_CNT]  = {15000, 20000, 25000}; 
    int         GAME :: lst_skill_clock[GAME :: WEAPON_CNT] = {0, 0, 0}; 
    const char *GAME :: WEAPON_NAME[GAME :: WEAPON_CNT]     = {"Machine Gun  ", "RPG          ", "Flame thrower"};
    const char *GAME :: SKILL_NAME[GAME :: WEAPON_CNT]      = {"Shock wave   ", "Grenade rain ", "Belief of FFF"};
    
    /*
     * main函数
    */
    int main() {
        srand(time(0));
        screen.init();
        debug = fopen("debug.out", "w");
        while(true) {
            Game.Init();
            Game.Rungame();
            Game.fail();
        }
        return 0;
    }
    /*
    
    使用说明:(V4.3)
    wasd控制玩家,
    方向键控制射击。
    空格放技能。
    shift切换武器。
    1,2,3选择武器。
    Q键返回上一个拿着的武器。
    P暂停。
    
    更新日志:
    
    V1.0 20200913
     - 实现了80 * n控制台显示。
     - 实现了kbhit + getch输入控制。
     - 加入了玩家对象、子弹对象、敌人对象、游戏运行对象。
     - 可以玩了。
     - 加入了失败页面,可以重新开始。
    
    V2.0 [ 操作更新 ] 20200918
     - 实现了GetKeyState和GetAsyncKeyState输入控制。
       - 可以边走边射击。
     - 将整数形式的移动改为实数形式,使得实体运动更加流畅。
       - 设置了圆形碰撞箱。取消了敌人的攻击距离。
     - 改为用方向键控制四向射击。
    
    V2.1 20200918
     - 实现了用四个键进行八向控制,包括玩家移动和射击。
       - 如果同时按了相对的两个键,就会忽略它;如果同时按了三个键,也会忽略那两个相对的,视为只按了中间那个。
    
    V2.2 20200920
     - 将储存实体(entity)的结构从数组改为链表,进行优化。
     - 敌人的运行方向连续化。
     - 常数优化。
    
    V2.3 20200920
     - 改变换帧方式,用clock()求得两次运行时间差,乘以速度进行换帧。
     - 玩家死亡之后,从(y/n)改为按空格重新开始。不想重新开始了就直接把窗口关掉好了。
    
    V2.4 20200920
     - 命令行窗口的每个字符的高宽是不同的,所以“斜上方”并不是45度。通过调整输出把这个问题解决了。
     - 修复了在场地边缘试图斜向行走时不能动的问题。
    
    V3.0 [ 战斗更新 ] 20200920
     - 两种敌怪,会有不同的速度和血量。也就是经典的“坚固笨重+脆弱迅速”组合。
     - 射击和敌怪攻击有了cd。
    
    V3.1 20200920
     - 射弹会随机偏转一个小角度。
     - 射弹会在玩家周围的某个范围内随机生成。范围可能不是以玩家中心对称的,而且方向由射弹的方向决定。
     - 加入了一个按空格发动的技能:向周围发射一圈冲击波。
    
    V3.2 20200920
     - 在上方显示玩家血条,技能加载条,和攻击的最后一个敌怪的血条。同时显示相应数字。
    
    V3.3 20200922
     - 对内核进行了较大改动。优化了对CPU的消耗。
    
    V3.4 20200922
     - 扩大了坚固笨重型敌怪的半径。
     - 在显示时,坚固笨重型敌怪会显示为大于一个字符大小的圆形。
     - 杀敌数统计改为分数统计。不同的敌怪分数不同。
     - 平衡性调整。当敌怪数量过多时会降低生成率。
    
    V3.5 20200924
     - 玩家的血量会缓慢恢复。
     - 低概率随机出现血瓶。
    
    V4.0 [ 射弹更新 ] 20200926
     - 可远程攻击的敌怪。
     - 两种武器。用shift切换。
    
    V4.1 20200927
     - 第三种武器。
     - 机枪的射速降低,伤害提高,精准度提高。
     - 调整了一些其他数据。
     - 一种火力更强、血量更高的炮塔类型敌怪。
     - 各个武器有独立的技能。
    
    V4.2 20200927
     - 加入暂停功能。
     - 改进了换武器的手感。
     - 用数字键切换武器,按q返回上一个拿着的武器。保留shift切换到下一个的功能。
     - 穿透武器会对敌怪造成无敌帧。
    
    V4.3 20201004
     - 改进了代码结构。
     - 攻击有了击退。
     - 有的实体会有一个逐渐加速的过程。
     - 炮台被击破时有特效。
    */
    
  • 相关阅读:
    孤荷凌寒自学python第114天区块链028以太坊智能合约007
    孤荷凌寒自学python第113天区块链027以太坊智能合约006
    孤荷凌寒自学python第112天认识区块链026
    孤荷凌寒自学python第111天区块链025eth智能合约004
    孤荷凌寒自学python第110天区块链024ETH智能合约003
    孤荷凌寒自学python第109天区块链023初识eth智能合约002
    孤荷凌寒自学python第108天区块链022之eth智能合约001
    孤荷凌寒自学python第106天认识区块链020
    孤荷凌寒自学python第105天认识区块链019
    Upenn树库的基本框架
  • 原文地址:https://www.cnblogs.com/lightmain-blog/p/13788528.html
Copyright © 2011-2022 走看看