#include <allegro.h>
#include <math.h>
#include <stdio.h>
#include "hunters.h"

#define ALLEGRO_NO_FIX_CLASS

typedef char string;


//main function
void main()
{
    //initialize
    allegro_init();
    install_keyboard();
    install_mouse();
    install_timer();
    set_color_depth(32);
    set_gfx_mode(MODE, WIDTH, HEIGHT, 0, 0);

    //load the fonts
    title = load_bitmap_font("HU FONT//tech.pcx", NULL, NULL);
    if (title == NULL)
        title = font;
    text = load_bitmap_font("HU FONT//main.pcx", NULL, NULL);
    if (text == NULL)
        text = font;

    //load the images
    //...

    //load the sounds
    //...

    //load the music
    //...

    //set the weapon names
    wpn[0] = "VULCAN CANNON";
    wpn[1] = "SPREADER RIFLE";
    wpn[2] = "RAILGUN";

    //set the mission paths
    lvl[0] = "HU MISSION//01.lvl";
    lvl[1] = "HU MISSION//02.lvl";
    lvl[2] = "HU MISSION//03.lvl";
    lvl[3] = "HU MISSION//04.lvl";
    lvl[4] = "HU MISSION//05.lvl";
    lvl[5] = "HU MISSION//06.lvl";
    lvl[6] = "HU MISSION//07.lvl";
    lvl[7] = "HU MISSION//08.lvl";
    lvl[8] = "HU MISSION//09.lvl";
    lvl[9] = "HU MISSION//10.lvl";
    lvl[10] = "HU MISSION//11.lvl";
    lvl[11] = "HU MISSION//12.lvl";
    lvl[12] = "HU MISSION//13.lvl";
    lvl[13] = "HU MISSION//14.lvl";
    lvl[14] = "HU MISSION//15.lvl";
    lvl[15] = "HU MISSION//16.lvl";
    lvl[16] = "HU MISSION//17.lvl";
    lvl[17] = "HU MISSION//18.lvl";
    lvl[18] = "HU MISSION//19.lvl";
    lvl[19] = "HU MISSION//20.lvl";

    //create a lookup table
    for (int a = 0; a < 360; a++)
    {
        sine[a] = sin(a/RAC);
        cosine[a] = cos(a/RAC);
    }

    //set up the random value
    srand(time(NULL));
    //initialize buffer
    buffer = create_bitmap(WIDTH, HEIGHT);
    //initialize player
    player.type = 0;
    player.hp = 100;
    player.x = WIDTH/2;
    player.y = HEIGHT/2;

    int color2 = BLACK;
    //reset loop number
    loop_num = 0;

    int intro = 0;

    //intro part 1
    while (intro < 110)
    {
    //log start time
    log_time = clock();

    //quick exit
    if (key[KEY_ENTER])
    {
        intro = 110;
        last_hit = clock();
    }

    //fade in
    if (intro < 20)
        color = color_shift(LIGHT_BLUE, BLACK, intro*5);
    
    //fade out
    if ((intro > 70)&&(intro < 91))
        color = color_shift(BLACK, LIGHT_BLUE, (intro-70)*5);

    //draw
    textout_centre_ex(buffer, title, "KIKARU",  512, 300, color, -1);
    textout_centre_ex(buffer, text, "PRESENTS:", 512, 370, color, -1);
    blit(buffer, screen, 0, 0, 0, 0, WIDTH, HEIGHT);
    clear_to_color(buffer, BLACK);

    //rest
    while (clock() < log_time + 20)
    {}
    
    //time goes on...
    intro += 1;
    }
    
    //title screen
    while (((!key[KEY_ENTER])&&(!key[KEY_ESC]))||(clock() < last_hit + 100))
    {
        //clear the buffer
        clear_to_color(buffer, BLACK);
        
        //make the title fade in
        if (loop_num < 200)
                color = color_shift(LIGHT_BLUE, BLACK, loop_num/2);
        
        //make the message blink
        else
        {
                if (loop_num % 200 < 100)
                        color2 = color_shift(LIGHT_BLUE, BLACK, loop_num%200);
                else
                        color2 = color_shift(LIGHT_BLUE, BLACK, 200-(loop_num%200));
        }
        
        //the title
        textprintf_centre_ex(buffer, title, 512, 300, color, -1, "%s", TITLE);
        
        //the message
        textout_centre_ex(buffer, text, "PRESS ENTER TO START", 512, 370, color2, -1);
        
        //draw to the screen
        blit(buffer, screen, 0, 0, 0, 0, WIDTH, HEIGHT);
        
        //rest
        while (clock() < log_time + 20)
        {}
        
        //keep track of the loop number
        loop_num += 1;
    }

    //quit from the title
    if (key[KEY_ESC])
        end_game = true;

    //reset loop number
    loop_num = 0;
    
    int tmish = 0;
    int mish_wind = 0;
    const int WIND_SIZE = 10;
    const int MISH_SPACE = HEIGHT/(WIND_SIZE+1);
    
    //mission select, official
    if (!end_game)
    {
    while ((!key[KEY_ENTER])||(loop_num < 75))
    {
         //log time
        log_time = clock();
        
        //move up
        if ((key[KEY_UP])&&(clock() > last_hit + 100))
        {
                tmish--;
                last_hit = clock();
        }

        //move down
        if ((key[KEY_DOWN])&&(clock() > last_hit + 100))
        {
                tmish++;
                last_hit = clock();
        }

        //limits!
        if (tmish > 19)
                tmish = 19;
        if (tmish < 0)
                tmish = 0;

        //scroll up
        if (tmish < mish_wind)
                mish_wind--;

        //scroll down
        if (tmish > mish_wind + WIND_SIZE)
                mish_wind++;

        //clear the buffer
        clear_to_color(buffer, BLACK);
    
        //drawing
        for (int i = mish_wind; i <= mish_wind + WIND_SIZE; i++)
        {
                if (i == tmish)
                        rectfill(buffer, 50, 10+MISH_SPACE*(i-mish_wind), WIDTH-520, 60+MISH_SPACE*(i-mish_wind), DARK_BLUE);
                rect(buffer, 50, 10+MISH_SPACE*(i-mish_wind), WIDTH-520, 60+MISH_SPACE*(i-mish_wind), LIGHT_BLUE);
                textprintf_ex(buffer, text, 65, 30+MISH_SPACE*(i-mish_wind), LIGHT_BLUE, -1, "MISSION %i%i: %s", (i+1)/10, (i+1)%10, "MISSION NAME HERE");
        }

        //draw to the screen
        blit(buffer, screen, 0, 0, 0, 0, WIDTH, HEIGHT);

        //rest
        while (clock() < log_time + 20)
        {}

        //keep track of the loop number
        loop_num += 1;
    }
    }

    //reset loop number... again...
    loop_num = 0;
    
    //select a mission
    if (!end_game)
    {
    //select the file
    if (file_select_ex("select a mission:", test_mission, "lvl", 80, 320, 240))
        end_game = false;
    //quit
    else
        end_game = true;
    }

    //from here...
    //load the test mission
    if (!end_game)
    {
    n_lvl.clear_mission();
    if (n_lvl.load_mission(test_mission))
        end_game = end_game;
    //not a valid file!
    else
    {
        end_game = true;
        clear_to_color(screen, BLACK);
        textprintf_centre_ex(screen, title, 512, 300, LIGHT_BLUE, -1, "ERROR:");
        textprintf_centre_ex(screen, text, 512, 370, LIGHT_BLUE, -1, "INVALID FILE. PRESS ESC TO QUIT.");
        while (!key[KEY_ESC])
        {}
    }
    }
    //...to here is just temporary!
        
    
    //the main game
    while (!end_game)
    {
        //log the start time
        log_time = clock()+20;
        
        //wait before spawning the next wave
        if ((num_enemies() == 0)&&(spawn_delay > 0))
                spawn_delay -= 1;
        
        //spawn the next wave
        if ((num_enemies() == 0)&&(spawn_delay <= 0))
        {
            
            //spawn the enemies
            if (progress < n_lvl.num_waves)
            {
                spawn_wave(n_lvl.wave[progress]);
                progress++;
            }

            //reset the delay
            spawn_delay = SPAWN_DELAY;
        }

        //update the player
        player.action();

        //quit if they press escape
        if (key[KEY_ESC])
                end_game = true;

        //update the shots
        for (int i = 0; i < 40; i++)
        {
                if (shot[i].hp > 0)
                        shot[i].action();
        }

        //update the enemies
        for (int n = 0; n < 80; n++)
        {
                if ((enemy[n].hp > 0)&&((enemy[n].enterance >= 10)))
                {
                        enemy[n].action();

                        //damage the player
                        if ((collision(enemy[n], player, HITBOX))&&(clock() > last_hit + HIT_DELAY))
                        {
                                if ((enemy[n].type == 1)||(enemy[n].type == 3))
                                        player.hp -= 10;
                                if (enemy[n].type == 2)
                                        player.hp -= 5;
                                if (enemy[n].type < 0)
                                {
                                        player.hp -= 5;
                                        enemy[n].hp = 0;
                                }
                                if (enemy[n].type == 4)
                                        player.hp -= 20;
                                //record time of last hit
                                last_hit = clock();
                        }

                        //enemies avoid each other
                        for (int i = 0; i < 80; i++)
                        {
                                
                                if (i == n)
                                        i++;
                                if (i >= 80)
                                        break;
                                
                                if ((enemy[i].hp > 0)&&(enemy[i].type > 0))
                                {
                                        if (collision(enemy[i], enemy[n], MOVEBOX))
                                        {
                                                repel(&enemy[i], &enemy[n], 2);
                                        }
                                }
                        }

                        //enemies collide with shots
                        for (int i = 0; i < 40; i++)
                        {
                                if ((shot[i].hp > 0)&&(enemy[n].hp > 0))
                                {
                                        if (collision(enemy[n], shot[i], HITBOX))
                                        {
                                                enemy[n].hp--;
                                                shot[i].hp = 0;
                                                enemy[n].x_spd += shot[i].x_spd;
                                                enemy[n].y_spd += shot[i].y_spd;
                                                if (shot[i].type == -2)
                                                        enemy[n].hp -= 2;
                                                if ((enemy[n].hp <= 0)&&(enemy[n].type >= 0))
                                                                enemy[n].explosion = 1;
                                        }
                                }
                        }
                }
                if ((enemy[n].hp <= 0)&&(enemy[n].explosion < 5)&&(enemy[n].explosion > 0))
                                enemy[n].explosion++;
                if ((enemy[n].hp > 0)&&(enemy[n].enterance < 10)&&(enemy[n].explosion > -11))
                                enemy[n].enterance++;
        }

        //set hp maximum
        if (player.hp < 0)
                player.hp = 0;

//drawing goes here
        //draw the player
        if (((clock() < last_hit + HIT_DELAY)&&((loop_num/2)%2 == 0))||(player.hp <= 0))
        {}
        else
        {
                circle(buffer, player.x, player.y, 16, GREEN);
                line(buffer, player.x, player.y, player.x + int(16*cosine[(player.dir)%360]), player.y + int(16*sine[(player.dir)%360]), GREEN);
        }
        //draw the shots
        for (int i = 0; i < 40; i++)
        {
                if (shot[i].hp > 0)
                        circle(buffer, shot[i].x, shot[i].y, 5, BLUE);
        }
        //draw the enemies
        for (int n = 0; n < 80; n++)
        {
                if (enemy[n].hp > 0)
                {
                        if ((enemy[n].hp > 0)&&(enemy[n].enterance < 10)&&(enemy[n].explosion > -10))
                        {
                                circle(buffer, enemy[n].x, enemy[n].y, 20 - abs(enemy[n].enterance*2), PURPLE);
                        }
                        else
                        {
                        switch (enemy[n].type)
                        {
                        //a missle
                        case -2:
                        circle(buffer, enemy[n].x, enemy[n].y, 6, RED);
                        break;

                        //a projectile
                        case -1:
                        circle(buffer, enemy[n].x, enemy[n].y, 4, RED);
                        break;

                        //a grunt
                        case 1:
                        circle(buffer, enemy[n].x, enemy[n].y, 16, RED);
                        line(buffer, enemy[n].x, enemy[n].y, enemy[n].x + int(16*cosine[(enemy[n].dir)%360]), enemy[n].y + int(16*sine[(enemy[n].dir)%360]), RED);
                        break;

                        //a hornet
                        case 2:
                        circle(buffer, enemy[n].x, enemy[n].y, 10, RED);
                        line(buffer, enemy[n].x, enemy[n].y, enemy[n].x + int(10*cosine[(enemy[n].dir)%360]), enemy[n].y + int(10*sine[(enemy[n].dir)%360]), RED);
                        break;

                        //a sniper
                        case 3:
                        circle(buffer, enemy[n].x, enemy[n].y, 16, RED);
                        line(buffer, enemy[n].x, enemy[n].y, enemy[n].x + int(16*cosine[(enemy[n].dir)%360]), enemy[n].y + int(16*sine[(enemy[n].dir)%360]), RED);
                        line(buffer, enemy[n].x, enemy[n].y, enemy[n].x - int(16*cosine[(enemy[n].dir)%360]), enemy[n].y - int(16*sine[(enemy[n].dir)%360]), RED);
                        break;

                        //a juggernaut
                        case 4:
                        circle(buffer, enemy[n].x, enemy[n].y, 20, RED);
                        line(buffer, enemy[n].x, enemy[n].y, enemy[n].x + int(20*cosine[(enemy[n].dir)%360]), enemy[n].y + int(20*sine[(enemy[n].dir)%360]), RED);
                        break;
                        }
                        }
                }
                //explosion!
                if ((enemy[n].hp <= 0)&&(enemy[n].explosion < 5)&&(enemy[n].explosion > 0))
                {
                                circle(buffer, enemy[n].x, enemy[n].y, enemy[n].explosion*MAX_HP[enemy[n].type]*3, ORANGE);
                }
        }

        //game over
        if (player.hp <= 0)
        {
                textout_centre_ex(buffer, title, "GAME OVER", WIDTH/2, HEIGHT/2-50, LIGHT_BLUE, -1);
        }

        //victory
        if ((progress >= n_lvl.num_waves)&&(num_enemies() <= 0))
        {
                textout_centre_ex(buffer, title, "MISSION COMPLETE", WIDTH/2, HEIGHT/2-50, LIGHT_BLUE, -1);
        }

        //tell the player how much health they have
        textprintf_ex(buffer, text, 10, 10, LIGHT_BLUE, -1, "%i%c POWER", player.hp, 37);

        //tell the player what weapon they are using
        textprintf_ex(buffer, text, 10, 25, LIGHT_BLUE, -1, "%s", wpn[weapon]);

        //show the mouse pointer
        circle(buffer, mouse_x, mouse_y, 8, GREEN);

        //draw to the screen
        blit(buffer, screen, 0, 0, 0, 0, WIDTH, HEIGHT);

        //save a screenshot
        if (key[KEY_TAB])
                save_bitmap("HU_SCREENSHOT.BMP", buffer, NULL);

        //clear the screen
        clear_to_color(buffer, BLACK);

        //rest
        while (clock() < log_time)
        {}

        //keep track of the loop number
        loop_num += 1;
    }

    //clean up
    destroy_bitmap(buffer);
    destroy_font(title);
    destroy_font(text);
    destroy_sample(eshot);
    destroy_sample(pshot);
    destroy_sample(slide);
    destroy_sample(blast);
    return;
}
END_OF_MAIN()
