/*********************************************************************
/***Project Name: Titans of New Earth                              ***
/***Programmer: Richard Cassan  aka  FrankyR                                   ***
/***Date Completed: June 17, 2001                                  ***
*********************************************************************/

/*Compiling instructions
	To compile, link the libraries 'alleg', and 'ppcol'

  Notes on the programming
  	I saved all of the different classes used in seperate .h files. The class
    defination, and all of the functions are saved in the same file.

    For sake of simpleness, all of the classes are included in a file called
    'side_class.h'.  It includes all of the other classes in the correct order

    CMap10.h is a set of classes that I made for use in several different
    programmes I have made.  It includes classes that have several uses in
    my game programming, like creating, saving, and drawing maps, as well as
    handling animations simply.
*/

/*#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include "allegro.h"

#include "CMap10.h"
#include "titans.h"
#include "side_class.h"
#include "ppcol.h"   */

#define PLAYER_NORM 0

#include <stdio.h>
#include <allegro.h>
#include <math.h>
#include "ppcol.h"
#include <time.h>

#include "CMap10.h"
#include "titans.h"
#include "side_class.h"

void startup(void);

void define_weapons(void);
void define_powerups(void);

void one_loop(void);
void draw_all(void);
void move_all(void);
void get_keys(void);

void define_player_atts(void);
void create_snow(void);
void init_enemies(void);
void create_explosion_anim(void);
void arm_player(void);
void create_tiles(void);
void load_map(char *file_name);
void create_pickups(void);
void load_tiles_into_map(void);
void define_circle_points(void);

void initalize_level(int n, int reset_lives, int reset_guns); //reset_lives 0=don't 1=do
void reset_player(void);

void menu(void);

void draw_help_bar(BITMAP *backgr, int x, int y, int n);

void draw_sprite_centre(BITMAP *backgr, BITMAP *pic, int x, int y);

void do_tut(void);

void go_sec(void);
volatile int sec=0;

void go_sec2(void);
volatile int sec2=0;

void calc_fps(void);

int cycles=0;
float fps=0;

float seconds=0;
float cycles_done=0;
int number_of_enemies=1;

int save_x, save_y;

int display_h=0;
int move_display_wait=0;
int move_display_dir=0;	   //0=down 1=up

//exit_game is 1 when the program is being quit
//play_game is 1 while a level is being played
//it is 0 when in the menu, or quitting
int exit_game=0, play_game=0;

int tut=0;   //0 means tutorial is not playing, 1 means it is
int tutorial_message=0;
int show_help=0, show_help_wait=0;

int fade=1;    //0 means don't fade, 1 means fade

void go_sec()
	{
    sec++;
	}
END_OF_FUNCTION(go_sec);

void calc_fps(void)
	{

     if(sec2>=5)
     	{
          fps=0;
          fps=cycles_done/sec2;
          sec2=0;
          cycles_done=0;
         }

     }
END_OF_FUNCTION(calc_fps);

void go_sec2()
	{
    sec2++;
	}
END_OF_FUNCTION(go_sec2);

BITMAP *backgr, *walk;
BITMAP *enim_pics[10], *enim_arm_pics[10];

DATAFILE *data;

CLayer main_layer,layer2;
CAnim expl;
explosion_set *explos = new explosion_set;

person player;
enemy enim[200];
pickup_set pickups,powerups_defined;

part_set particles;
CTile tile1[30];   //an array of map tiles

CAnim red_crystal_anim,blue_crystal_anim, green_crystal_anim;
//creates weapon types, and attribute sets for projectiles
part_att gun_part[10];
weapon gun[10];

att_set atts[10]; //10 different attribute sets for objects

wdisplay display;

int old_level=0;

void startup(void)
	{
     allegro_init();
     install_keyboard();
     install_timer();
     install_mouse();
     set_gfx_mode(GFX_SAFE,640,480,0,0);
     install_sound(DIGI_AUTODETECT,MIDI_AUTODETECT,NULL);
     //dime_init();
     srand(1);

     data=load_datafile("titans.dat");
     set_pallete((RGB*)data[pal].dat);

     backgr=create_bitmap(640,480);
     walk=create_bitmap(640,480);

     initalize_level(1,1,1);

     text_mode(-1);

     display.init();

     //creates the transluscent colour table
      if(( color_map = (COLOR_MAP*)malloc( sizeof( COLOR_MAP) )) == NULL)
        {
         printf("Unable to allocate colour map!\n");
         exit( 1);
        }
      //it uses 230/255 for the red green and blue values
     create_trans_table(color_map,(RGB*)data[pal].dat, 230, 230, 230, NULL);



     LOCK_VARIABLE(sec);
     LOCK_VARIABLE(sec2);

     LOCK_FUNCTION(go_sec);
	 LOCK_FUNCTION(go_sec2);

     LOCK_FUNCTION(calc_fps);
     install_int_ex(go_sec, BPS_TO_TIMER(20));
     install_int_ex(go_sec2, BPS_TO_TIMER(1));
	}

void define_weapons(void)
	{
     //this set stores info for how a projectile will act
     gun_part[1].max_speed=20;
     gun_part[1].accel=20;
     gun_part[1].damage=7;
     gun_part[1].pic=(BITMAP*)data[bullet2].dat;
     gun_part[1].cool=3;
     gun_part[1].recoil=.25;
     gun_part[1].ammo_type=0;
     gun_part[1].grav=0;
     gun_part[1].explode=0;
     gun_part[1].expl=NULL;
     gun_part[1].shell_pic=(BITMAP*)data[shell].dat;
     gun_part[1].sound = (SAMPLE*)data[shot1].dat;

     //this creates a gun with rect as it's picture, and the above atts for it's
     //projectiles
     gun[1].init((BITMAP*)data[gun2].dat,gun_part[1],0,20,"Machine Gun");

     //this set stores info for how a projectile will act
     gun_part[2].max_speed=20;
     gun_part[2].accel=20;
     gun_part[2].damage=35;
     gun_part[2].pic=(BITMAP*)data[bullet1].dat;
     gun_part[2].cool=19;
     gun_part[2].recoil=4;
     gun_part[2].ammo_type=0;
     gun_part[2].grav=0;
     gun_part[2].explode=0;
     gun_part[2].expl=NULL;
     gun_part[2].shell_pic=(BITMAP*)data[shell2].dat;
     gun_part[2].sound = (SAMPLE*)data[shotgun_sound].dat;

     //this creates a gun with rect as it's picture, and the above atts for it's
     //projectiles
     gun[2].init((BITMAP*)data[gun3].dat,gun_part[2],0,22,"Shot Gun");

     gun_part[0].max_speed=20;
     gun_part[0].accel=20;
     gun_part[0].damage=15;
     gun_part[0].pic=(BITMAP*)data[bullet2].dat;
     gun_part[0].cool=15;
     gun_part[0].recoil=1;
     gun_part[0].ammo_type=0;
     gun_part[0].grav=0;
     gun_part[0].explode=0;
     gun_part[0].expl=NULL;
     gun_part[0].shell_pic=(BITMAP*)data[shell].dat;
     gun_part[0].sound = (SAMPLE*)data[shot1].dat;
     gun[0].init((BITMAP*)data[gun1].dat,gun_part[0],0,20,"Standard Gun");

     //**NOTE** damage from an explosion is done many times during the explosion
     //so a low value for damage will still do quite a lot
     gun_part[3].max_speed=12;   //12
     gun_part[3].accel=12;        //12
     gun_part[3].damage=3;
     gun_part[3].pic=(BITMAP*)data[grenade_pic].dat;
     gun_part[3].cool=15;
     gun_part[3].recoil=1;
     gun_part[3].ammo_type=0;
     gun_part[3].grav=1;
     gun_part[3].explode=1;
     gun_part[3].expl=explos;
     gun_part[3].shell_pic=(BITMAP*)data[shell].dat;
     gun_part[3].sound = (SAMPLE*)data[shot1].dat;
     gun[3].init((BITMAP*)data[gun4].dat,gun_part[3],0,20,"Grenade");

	}

void define_powerups(void)
	{
     powerups_defined.create_new(0,0,(BITMAP*)data[machine_pickup].dat,1,(SAMPLE*)data[reload].dat,1); //machine gun
     powerups_defined.create_new(0,0,(BITMAP*)data[shot_pickup].dat,2,(SAMPLE*)data[reload].dat,2); //shot gun
     powerups_defined.create_new(0,0,(BITMAP*)data[grenade_pickup].dat,3,(SAMPLE*)data[reload].dat,3); //grenade

     blue_crystal_anim.init();
     blue_crystal_anim.add_bmp((BITMAP*)data[crystal1].dat);
     blue_crystal_anim.add_bmp((BITMAP*)data[crystal2].dat);
     blue_crystal_anim.add_bmp((BITMAP*)data[crystal3].dat);
     blue_crystal_anim.add_bmp((BITMAP*)data[crystal4].dat);
     blue_crystal_anim.add_bmp((BITMAP*)data[crystal5].dat);

     red_crystal_anim.init();
     red_crystal_anim.add_bmp((BITMAP*)data[crystal_r1].dat);
     red_crystal_anim.add_bmp((BITMAP*)data[crystal_r2].dat);
     red_crystal_anim.add_bmp((BITMAP*)data[crystal_r3].dat);
     red_crystal_anim.add_bmp((BITMAP*)data[crystal_r4].dat);
     red_crystal_anim.add_bmp((BITMAP*)data[crystal_r5].dat);

     green_crystal_anim.init();
     green_crystal_anim.add_bmp((BITMAP*)data[crystal_g1].dat);
     green_crystal_anim.add_bmp((BITMAP*)data[crystal_g2].dat);
     green_crystal_anim.add_bmp((BITMAP*)data[crystal_g3].dat);
     green_crystal_anim.add_bmp((BITMAP*)data[crystal_g4].dat);
     green_crystal_anim.add_bmp((BITMAP*)data[crystal_g5].dat);

     powerups_defined.create_new(0,0,(BITMAP*)data[medkit_pic].dat,10,(SAMPLE*)data[medkit_sound].dat,10);
     powerups_defined.create_new(0,0,(BITMAP*)data[disk1].dat,11,(SAMPLE*)data[disk_sound].dat,11);
     powerups_defined.create_new(0,0,&blue_crystal_anim,12,(SAMPLE*)data[crystal_sound].dat,12);
     powerups_defined.create_new(0,0,&red_crystal_anim,13,(SAMPLE*)data[crystal_sound].dat,13);
     powerups_defined.create_new(0,0,&green_crystal_anim,14,(SAMPLE*)data[crystal_sound].dat,14);
    }

void draw_all(void)
	{
     int n;
     //clears the bitmaps
     //rectfill(backgr,0,0,640,480,248);
    // blit((BITMAP*)data[sky].dat,backgr,0,0,0,0,640,480);

     if(player.ret_p_x()>-1280)
     	blit((BITMAP*)data[mountain].dat,backgr,
             (int)player.ret_p_x(),
             (int)player.ret_p_y()/*-20*/,
             0,
             0,640,480);

     rectfill(walk,0,0,640,480,0);

     //draw some of the snowflakes behind everything
     particles.draw_some(backgr,player.get_sx(),player.get_sy(),0,100);

     //draws main layer onto backgr using the player's screen positions
     layer2.draw_layer(backgr,walk,0,0,player.get_sx(),player.get_sy(),0,0); //draw the map layer
     main_layer.draw_layer(backgr,walk,0,0,player.get_sx(),player.get_sy(),0,0); //draw the map layer

     //draws all of the pickups onto the backgr relative to the player's x,y
     //screen position
     pickups.draw_all(backgr,player.get_sx(),player.get_sy());

     //draws the player, his gun and all his projectiles onto the screen using
     //the player's screen position
     player.draw(backgr, player.get_sx(), player.get_sy());
     player.draw_proj(backgr, player.get_sx(), player.get_sy());
     player.draw_gun(backgr, player.get_sx(), player.get_sy());

     //draws the enemy, his gun, and all his projectile onto the screen using
     //the player's screen position
     for(n=0 ; n < number_of_enemies ; n++)
        {
         //only draws enemy if it is near the screen and it exists
        if(enim[n].exist==1)
          {
           if(enim[n].ret_x()-player.get_sx()<740 &&
              enim[n].ret_x()-player.get_sx()>-100 &&
              enim[n].ret_y()-player.get_sy()<580 &&
              enim[n].ret_y()-player.get_sy()>-100)
          	  {
     		  enim[n].draw(backgr, player.get_sx(), player.get_sy());

     		  enim[n].draw_gun(backgr,player.get_sx(), player.get_sy());
     		  enim[n].draw_life(backgr,player.get_sx(),player.get_sy());
        	  }
           //draw the projectiles whether or not the enemy is on the screen
           enim[n].draw_proj(backgr, player.get_sx(), player.get_sy());
          }
     	}



     //draws all of the exposions onto the background
     explos->draw_all(backgr,player.get_sx(),player.get_sy());

     particles.draw_some(backgr,player.get_sx(),player.get_sy(),100,200); //draw half
     //of the snowflakes infront of everything


     draw_trans_sprite(backgr,(BITMAP*)data[bottom_bar].dat,0,390+display_h);
     //draws the display info onto the screen
     player.draw_port(backgr,555,410+display_h);
     player.write_wep_name(backgr,200,405+display_h,(FONT*)data[title_font].dat);
     player.draw_life(backgr,200,450+display_h);
     player.draw_ammo(backgr,225,440+display_h,(FONT*)data[title_font].dat);
      //draws all of the player's keys
     player.draw_keys(backgr,(BITMAP*)data[disk1].dat,10,450+display_h);


     textprintf(backgr,font,0,0,10,"fps: %f",fps);

     textprintf(backgr,(FONT*)data[info_font].dat,0,10,133,"Level: %d",player.ret_level());
     textprintf(backgr,(FONT*)data[info_font].dat,0,40,133,"Lives: %d",player.ret_lives());

     textprintf_right(backgr,font,630,10,110,"Hit the 'H' key to activate the help");
     textprintf_right(backgr,font,630,21,110,"Hit the 'E' key to minimize the info bar at the bottom");

     if(show_help==1)
       {
     	draw_help_bar(backgr,320,100,tutorial_message);
       }

     display.write_message(backgr,(FONT*)data[info_font].dat,108);

     //draws the background onto the screen (double buffering)
     if(!key[KEY_Q])
     	blit(backgr,screen,0,0,0,0,640,480);
     else
        blit(walk,screen,0,0,0,0,640,480);

     if(fade==1)
       {
        fade_in((RGB*)data[pal].dat,1);
        fade=0;
        cycles=0;
        sec=0;
       }

	}

void move_all(void)
	{
     int n;
     int drop=-1;

     if(player.ret_level() ==-1) //level of -1 means the player lost a life
       {
        player.lives_down();  //player looses a life
        reset_player();       //rest all of the player's info
        initalize_level(old_level,0,1);  //reset level, but do not reset lives, do reset guns
        player.set_level(old_level);   //set the player's level
        fade=1;               //set flag to fade in next oppertunity
        fade_out(1);
       }
     else if(player.ret_level() ==-2) //means lost lives
       {
        play_game=0;
        fade_out(1);
        }

       //don't beat level if the player is in the tutorial
     else if(player.ret_level() != old_level && tut==0)
       initalize_level(player.ret_level(),0,0);


     if(tut==0)      //only get keys if not watching tutorial
     	get_keys();  //gets keys from user
     else if(tut==1)
       do_tut();

     player.friction();

     player.move_proj(&main_layer);        //move the player's projectiles
     player.move(&main_layer);  //move the player

     //check to see if any of the powerups hit the player
     pickups.collide_all(&player, &display);

     player.check_expl_hit(explos);

     player.check_die();

     particles.move_to_top(player.get_sx(),player.get_sy());
     particles.move_all(0);

     //enim[3].fire();

     for(n=0 ; n<number_of_enemies ; n++)
        {
         //only moves enemy if it is near the screen, and it exists
        if(enim[n].exist==1)
          {

           //move and detect the projectiles whether or not the enemy is on
           //the screen:

           //check to see if any of the enemy's projectiles
           //hit the player
           player.check_hit(&enim[n]);
           //move all of the enemy's projectiles
           enim[n].move_proj(&main_layer);


           //only is the enemy is on the screen
           if(enim[n].ret_x()-player.get_sx()<740 &&
              enim[n].ret_x()-player.get_sx()>-100 &&
              enim[n].ret_y()-player.get_sy()<580 &&
              enim[n].ret_y()-player.get_sy()>-100)
              {
               //adjusts the aim of the gun to point at the player
        	   enim[n].get_target_angle(&player);

               //checks to see if the enemy is hit with any exposions
               //and adjusts life approprately
               enim[n].check_expl_hit(explos);

               //the move function returns a value 1 if the object hit
               //something moving left or right
        	   if (enim[n].move(&main_layer)==1)
                 {
                 //for the sake of the AI, if it hit a wall while moving
                 //left or right it should turn around.
                 enim[n].switch_dir();
                 }
           	     //check to see if any of the player's projectiles hit the enemy
               enim[n].check_hit(&player);

               //if the enemy is destroyed, and the enemy drops somthing,
               //it returns the number of the pickup it dropped
               //if it did not die it returns -1
               //if it died, but didn't drop anything it returns -2
               drop=enim[n].check_die();

               if(drop!=-1)  //he died
                 {
                  explos->create_new(enim[n].ret_x()-150,
                                     enim[n].ret_y()-70,
                                     2);
                 }

               //set's the enemy's movement pattern
               //enim[n].patrol_norm(enim[n].ret_lx(),enim[n].ret_rx(),1);
               enim[n].patrol_norm(enim[n].ret_lx(),enim[n].ret_rx(),1);

               //if it dropped something
              if(drop!=-2 && drop!=-1 )
                 {
                  //then it will create a new powerup for the weapon it dropped
         	      pickups.create_from(powerups_defined.ret_pickup(drop),
                      enim[n].ret_x(),enim[n].ret_y());
                 }
              }
           }
        else   //if the enemy does not exist, or it is not on screen
          {
           //destroy all of it's projectiles
           enim[n].destroy_proj();
          }
        }
     if(move_display_wait>0)
       {
     	move_display_wait-=3;
        if(move_display_dir==0)
          display_h-=3;
        else if(move_display_dir==1)
          display_h+=3;
       }
     if(show_help_wait>0)
       show_help_wait--;

     display.move_message();

     if(tut==0 && cycles%43==0)  //if not playing tutorial
     	{
         //cycles through all of the help messages, changing every
         //40 cycles
        tutorial_message++;
        if(tutorial_message>12)
        	tutorial_message=0;
        }

    }

void get_keys(void)
	{
     if(key[KEY_RIGHT])
       {
        player.on_right();
       }
     else if(key[KEY_LEFT])
       {
        player.on_left();
       }
     else
       {
        player.friction();
       }

     if(key[KEY_UP])
       {
        player.on_up();
       }
     else if(key[KEY_DOWN])
       {
        player.on_down();
       }
     else
        player.not_up_or_down();

     if(key[KEY_LCONTROL])
       {
        player.on_jump();

       }
     if(key[KEY_SPACE])
       {
        player.fire();
       }

     if(key[KEY_A])
       {
        player.prev_gun();
       }
     else if(key[KEY_S])
    	{
         player.next_gun();
        }

     if(key[KEY_D])
       {
        player.toggle_crouch();
       }

     if(key[KEY_Z])
       initalize_level(2,0,0);

     if(key[KEY_E] && move_display_wait<=0)
       {
        move_display_wait=100;
        if(move_display_dir==0)
          move_display_dir=1;
        else if(move_display_dir==1)
          move_display_dir=0;
       }

     if(key[KEY_W])
      {
       BITMAP *shot;
       shot=create_sub_bitmap(screen,0,0,SCREEN_W,SCREEN_H);
       save_bitmap("screenshot2.pcx",shot,(RGB*)data[pal].dat);
       destroy_bitmap(shot);
       destroy_bitmap(shot);
      }

     if(key[KEY_H] && show_help_wait==0)
       {
        show_help_wait=10;
        if(show_help==0)
          show_help=1;
        else if(show_help==1)
          show_help=0;
       }
 	}

void define_player_atts(void)
	{
     //loads in the pictures for three enemies
     enim_pics[0]=(BITMAP*)data[enim_pic].dat;
     enim_pics[1]=(BITMAP*)data[probe1].dat;
     enim_pics[2]=(BITMAP*)data[enim2_pic].dat;

     enim_arm_pics[0]=(BITMAP*)data[arm_enim].dat;
     enim_arm_pics[1]=(BITMAP*)data[enim2_arm].dat;
     enim_arm_pics[2]=(BITMAP*)data[enim3_arm].dat;

     //sets the values for the first attribute set (the player)
     atts[PLAYER_NORM].max_speed=7;
     atts[PLAYER_NORM].accel=2.3;
     atts[PLAYER_NORM].term_vel=20;
     atts[PLAYER_NORM].j_speed=25;
    }

void create_snow(void)
	{
     float x,y;
     float r;
     int r2;
     //sets up 200 particles as snowflakes created at random positions
     for(int n=0 ; n<200 ; n++)
        {
        x=rand()%800;
        y=rand()%800;
        y-=200;

        r2=rand()%6;
        r2+=4;
        r=r2;
        r/=10;
     	particles.create_new(x,y,0,(BITMAP*)data[snowflake].dat,
                             1,(float)0,r);
        }
     }

void init_enemies(void)
	{
     //creates the 100 enemies with default settings
     //they are non-existant to start, and will only become existant
     //if they are loaded in from a map
     for(int n=0 ; n<100 ; n++)
     	{
     	enim[n].init((BITMAP*)data[probe1].dat,
     	(BITMAP*)data[probe1].dat,
     	(BITMAP*)data[enim2_arm].dat,
        (BITMAP*)data[probe1].dat,
     	atts[PLAYER_NORM],320,240);
     	enim[n].init2(1);
     	}
     }

void create_explosion_anim(void)
	{
     expl.init(); //initializes the animation

     //loads in all the frames of animation for the explosion from the
     //datafile
     expl.add_bmp((BITMAP*)data[exp1].dat);
     expl.add_bmp((BITMAP*)data[exp2].dat);
     expl.add_bmp((BITMAP*)data[exp3].dat);
     expl.add_bmp((BITMAP*)data[exp4].dat);
     expl.add_bmp((BITMAP*)data[exp5].dat);
     expl.add_bmp((BITMAP*)data[exp6].dat);
     expl.add_bmp((BITMAP*)data[exp7].dat);
     expl.add_bmp((BITMAP*)data[exp8].dat);
     expl.add_bmp((BITMAP*)data[exp9].dat);
     expl.add_bmp((BITMAP*)data[exp10].dat);
     expl.add_bmp((BITMAP*)data[exp11].dat);
     expl.add_bmp((BITMAP*)data[exp12].dat);
     expl.add_bmp((BITMAP*)data[exp13].dat);
     expl.add_bmp((BITMAP*)data[exp14].dat);
     expl.add_bmp((BITMAP*)data[exp15].dat);
     expl.add_bmp((BITMAP*)data[exp16].dat);
     expl.add_bmp((BITMAP*)data[exp17].dat);
     expl.add_bmp((BITMAP*)data[exp18].dat);
     expl.add_bmp((BITMAP*)data[exp19].dat);
     expl.add_bmp((BITMAP*)data[exp20].dat);
     expl.add_bmp((BITMAP*)data[exp21].dat);
     expl.add_bmp((BITMAP*)data[exp22].dat);
     expl.add_bmp((BITMAP*)data[exp23].dat);
     expl.add_bmp((BITMAP*)data[exp24].dat);
     expl.add_bmp((BITMAP*)data[exp25].dat);
     expl.add_bmp((BITMAP*)data[exp26].dat);
     expl.add_bmp((BITMAP*)data[exp27].dat);
     }

void arm_player(void)
	{
     player.clear_guns();  //clear all of the player's guns

     //all guns are added to the player in the correct order at the start
     //so gun[0] is the player's first gun. The player will always have
     //all of the guns, but will only be able to select those with ammo.

     //gives all of the guns to the player in the correct order
     //with the default ammount of ammo

     //adds gun 0 to the players arsenal with ammo of -1 (unlimited)
     gun[0].set_ammo(-1);
     player.add_gun(gun[0]);

     //adds the gun to the players arsenal
     gun[1].set_ammo(100);
     player.add_gun(gun[1]);

     gun[2].set_ammo(10);
     player.add_gun(gun[2]);

     gun[3].set_ammo(0);
     player.add_gun(gun[3]);
    }

void create_tiles(void)
	{
     tile1[1].init();
     tile1[1].load_tile((BITMAP*)data[g1].dat, (BITMAP*)data[g1_walk].dat,1);

     tile1[2].init();
     tile1[2].load_tile((BITMAP*)data[g2].dat, (BITMAP*)data[g1_walk].dat,2);

     tile1[3].init();
     tile1[3].load_tile((BITMAP*)data[g3].dat, (BITMAP*)data[g1_walk].dat,3);

     tile1[4].init();
     tile1[4].load_tile((BITMAP*)data[g4].dat, (BITMAP*)data[g1_walk].dat,4);

     tile1[5].init();
     tile1[5].load_tile((BITMAP*)data[g5].dat, (BITMAP*)data[g1_walk].dat,5);

     tile1[6].init();
     tile1[6].load_tile((BITMAP*)data[g6].dat, (BITMAP*)data[g1_walk].dat,6);

     tile1[7].init();
     tile1[7].load_tile((BITMAP*)data[g7].dat, (BITMAP*)data[g1_walk].dat,7);

     tile1[8].init();
     tile1[8].load_tile((BITMAP*)data[g8].dat, (BITMAP*)data[g1_walk].dat,8);

     tile1[9].init();
     tile1[9].load_tile((BITMAP*)data[g9].dat, (BITMAP*)data[g1_walk].dat,9);

    }

void load_map(char *file_name)
	{
     save_x=0;
     save_y=0;
     FILE *fp;
     fp=fopen(file_name,"r");

     fscanf(fp,"%d",&number_of_enemies);

     fscanf(fp,"%d",&save_x);
     fscanf(fp,"%d",&save_y);

     for(int n=0 ; n<number_of_enemies ; n++)
        {
          enim[n].load_emim(fp);

          gun[enim[n].get_wep_no()].set_ammo(-1);
          enim[n].add_gun(gun[enim[n].get_wep_no()]);

          enim[n].set_pic(enim_pics[enim[n].pic_num],enim[n].pic_num);
          enim[n].set_arm_pic(enim_arm_pics[enim[n].pic_num]);
  
          //enim[n].exist=1;
         }

     pickups.load_all(fp);

     main_layer.load_layer(fp); //loads map
     layer2.load_layer(fp); //loads map

     fclose(fp);
    }

void create_pickups(void)
	{
     for(int n=0; n<59 ; n++)
        {
         if(pickups.get_exist(n)==1)
         pickups.create_from(powerups_defined.ret_pickup(pickups.get_type(n)),
                      pickups.get_x(n),pickups.get_y(n));
        }
    }

void load_tiles_into_map(void)
	{
      for(int x=0;x<200;x++)//goes through map
        for(int y=0 ; y<200 ; y++)
           {
            main_layer.load_tile(tile1[main_layer.get_tile_no(x,y)],x,y);//set it to the proper picture
            layer2.load_tile(tile1[layer2.get_tile_no(x,y)],x,y);
           }
    }

void define_circle_points(void)
	{
     //these circle points are used to draw the player's life
     int c=147;  //c just keeps track of the colour for the line
     int counter=16;
     for(int a=0 ; a<256 ; a++)
      	{
         //goes through the 256 degrees in the circle, and defines the
         //relative x ant y positions to make a circle radius 20
         circle_points[a].x= (sin( (a*1.40625) *M_PI/180))*20;
         circle_points[a].y= (-cos( (a*1.40625) *M_PI/180))*20;
         circle_points[a].c=c;

         //this stuff just gets the right colour from the pallete
         counter--;
         if(counter==0)
           {
           counter=16;
           c--;
           }
         if(c==138)
           c=77;
         if(c==72)
           c=111;
        }
	}

void initalize_level(int n, int reset_lives, int reset_guns)
	{
     //defines the attributes
     define_player_atts();

     //initializes the particles (snow)
     particles.init();

     player.init2(n, reset_lives);   //initialize for level 1

     create_snow(); //creates and postions particles as snowflakes

     init_enemies(); //initalizes all enemies in default

     pickups.init();  //initalizes the game pickups
     powerups_defined.init(); //initalizes the set of pickups that the others
     //will be based upon

     create_explosion_anim(); //creates the animation for the explosion

     //initalizes the set of explosions using the animation created above,
     //and the explosion sound
     explos->init(expl,(SAMPLE*)data[explosion_sound].dat);

     //defines all of the weapons (the arrays of gun and gun_part)
     define_weapons();

     //defines all of the powerups. It creates powerups in the powerups_defined
     //member, they can then be copied into the game powerups
     define_powerups();

     if(reset_guns==1)//only re-arm the player if the flag is set
       {
     	//gives the player all of the weapons
     	arm_player();
       }

     //creates all of the tile prototypes
     create_tiles();

     //initalizes the two layers with:
     //200 tiles by 200 tiles
     //each tile is 32 pixels by 32 pixels
     //the screen size is 640 X 480
     main_layer.init(1,200,200,32,32,640,480);
     layer2.init(1,200,200,32,32,640,480);

     char file_name[100] ="";

     //n refers to the level to load
     if(n==0)    //load the tutorial
       {
        strcpy(file_name,"tut.map");
        old_level=0;
       }
     else if(n==1)  //load the first level map
       {
       strcpy(file_name,"new1.map");
       old_level=1; //set the level number to 1
       }
     else if(n==2)  //load the second level map
       {
       strcpy(file_name,"map7.map");
       old_level=2;
       }
     else   //if no level number is specified, then load level 1
       {
       strcpy(file_name,"map6.map");
       old_level=1;
       player.set_level(1);
       }

     //loads the map file info into the classes
    save_x=0;
    save_y=0;
    load_map(file_name);

    //move the player to the starting position from the map
    player.move_to((float)save_x,(float)save_y);

    //creates the game pickups from the defined powerups in the places load
    //from the map file
    create_pickups();

    //load the tiles into the game map in the places from the map file
    load_tiles_into_map();

    define_circle_points();

    if(old_level==1)
    	display.set_message("Level 1",320,490,0,-7);
    else if(old_level==2)
        display.set_message("Level 2",320,490,0,-7);
    else if(old_level==3)
        display.set_message("Level 3",320,490,0,-7);
    else if(old_level==4)
        display.set_message("Level 4",320,490,0,-7);
    else if(old_level==5)
        display.set_message("Level 5",320,490,0,-7);

    //fade_in((RGB*)data[pal].dat,1);

    cycles=0;
    sec=0;
   }

void reset_player(void)
	{
     player.init((BITMAP*)data[character].dat,
     	 (BITMAP*)data[character_jump].dat,
     	 (BITMAP*)data[arm].dat,
     	 (BITMAP*)data[crouch].dat,
      	 atts[PLAYER_NORM],320,240);
     player.set_port((BITMAP*)data[yellow_head].dat);
     
     player.set_scroll_speed(3);
    }

void menu(void)
	{
     int selection=0;   //number for which option is selected
     int end_menu=0; //flag set to one when the menu is exited
     int loops=0;
     float sx=0,sy=0,  //for the screen position of the map in the background
      mx=3,my=1;        //for the movement values of the map in the bakcground

     int change_selection_wait=0;

     particles.init();
     create_snow();

     sec=0;
     cycles=0;

     //load_map("map6.map");
     //initalize level 1 by default
     initalize_level(1,1,1);

     stop_midi();
     play_midi((MIDI*)data[title_music].dat, TRUE);
     while(end_menu==0)
       {
        if(sec>cycles)
          {
           cycles++;
     	   rectfill(backgr,0,0,640,480,0);

        	//draws the starts onto the background
        	draw_sprite(backgr,(BITMAP*)data[stars].dat,0,0);

        	//draws the map onto the background
        	main_layer.draw_layer(backgr,walk,0,0,sx,sy,0,0);
        	particles.draw_all(backgr,sx,sy);

        	draw_sprite(backgr,(BITMAP*)data[title_words].dat,20,20);

        	textprintf_centre(backgr,(FONT*)data[title_font].dat,320,300,90,"Play Game");
        	textprintf_centre(backgr,(FONT*)data[title_font].dat,320,330,90,"Tutorial");
        	textprintf_centre(backgr,(FONT*)data[title_font].dat,320,360,90,"Exit");

        	if(key[KEY_UP] && change_selection_wait==0)
          	    {
            	selection--;
            	change_selection_wait=5;
            	play_sample((SAMPLE*)data[shot1].dat,255,128,1000,FALSE);
            	}
        	else if(key[KEY_DOWN] && change_selection_wait==0)
            	{
            	selection++;
            	change_selection_wait=5;
            	play_sample((SAMPLE*)data[shot1].dat,255,128,1000,FALSE);
            	}

        	if(key[KEY_ENTER])
            	{
            	end_menu=1;
            	play_sample((SAMPLE*)data[shotgun_sound].dat,255,128,1000,FALSE);
                fade_out(1);
                stop_midi();
                }

        	if(selection>2)
            	selection=0;
        	else if(selection<0)
            	selection=2;

        	if(selection==0)
     	       textprintf_centre(backgr,(FONT*)data[title_font].dat,320,300,80,"Play Game");
        	else if(selection==1)
     	       textprintf_centre(backgr,(FONT*)data[title_font].dat,320,330,80,"Tutorial");
        	else if(selection==2)
     	       textprintf_centre(backgr,(FONT*)data[title_font].dat,320,360,80,"Exit");

        	blit(backgr,screen,0,0,0,0,640,480);

            if(fade==1)
              {
               fade_in((RGB*)data[pal].dat,1);
               fade=0;
               cycles=0;
        	   sec=0;
              }

        	sx+=mx;
        	sy+=my;

        	if(change_selection_wait>0)
        	   change_selection_wait--;

        	particles.move_to_top(sx,sy);
        	particles.move_all(0);

        	if(sx>2000 || sx<0)
            	mx*=-1;
        	if(sy>100 || sy<0)
            	my*=-1;
          	}
	    }

       if(selection==0)	//play game
         {
          //creates the player with the first attribute set
     	 //uses the pictures defined below
          reset_player();

          initalize_level(1,1,1);//initalize level for
          //level 1, and do reset lives
          play_game=1;
          tut=0;  //not in the tutorial
          show_help=0;
          fade=1;
          play_midi((MIDI*)data[game_music].dat, TRUE);
         }
       else if(selection==1) //watch tutorial
         {
          reset_player();
          initalize_level(0,1,1);  //level 0 is for tutorial
          play_game=1;
          tut=1;
          fade=1;
          play_midi((MIDI*)data[game_music].dat, TRUE);
         }

       else if(selection==2) //exit
         {
          exit_game=1;
          play_game=0;
         }
       sec=0;
       cycles=0;
       key[KEY_ESC]=false;
    }


void draw_help_bar(BITMAP *backgr, int x, int y, int n)
	{
     if(n==1)
       {
        textprintf_centre(backgr,font,x,y,108,"Hit the up arrow to aim up");
        draw_sprite_centre(backgr,(BITMAP*)data[arrow_up].dat,x,y+30);
       }
     else if(n==2)
       {
        textprintf_centre(backgr,font,x,y,108,"Hit the down arrow to aim down");
        draw_sprite_centre(backgr,(BITMAP*)data[arrow_down].dat,x,y+30);
       }
     else if(n==3)
       {
        textprintf_centre(backgr,font,x,y,108,"Hit the left arrow to move left");
        draw_sprite_centre(backgr,(BITMAP*)data[arrow_left].dat,x,y+30);
       }
     else if(n==4)
       {
        textprintf_centre(backgr,font,x,y,108,"Hit the right arrow to move right");
        draw_sprite_centre(backgr,(BITMAP*)data[arrow_right].dat,x,y+30);
       }
     else if(n==5)
       {
        textprintf_centre(backgr,font,x,y,108,"Hit the Ctrl key to jump");
        draw_sprite_centre(backgr,(BITMAP*)data[letter_ctrl].dat,x,y+30);
       }
     else if(n==6)
       {
        textprintf_centre(backgr,font,x,y,108,"Hit the S key for next gun");
        draw_sprite_centre(backgr,(BITMAP*)data[letter_s].dat,x,y+30);
       }
     else if(n==7)
       {
        textprintf_centre(backgr,font,x,y,108,"Hit the A key for the previous gun");
        draw_sprite_centre(backgr,(BITMAP*)data[letter_a].dat,x,y+30);
       }
     else if(n==8)
       {
        textprintf_centre(backgr,font,x,y,108,"Hit the Space key to shoot");
        draw_sprite_centre(backgr,(BITMAP*)data[letter_sp].dat,x,y+30);
       }
     else if(n==9)
       {
        textprintf_centre(backgr,font,x,y,108,"Pick up boxes for ammo");
        }
     else if(n==10)
       {
        textprintf_centre(backgr,font,x,y,108,"Some enemies will drop items when they die");
       }
     else if(n==11)
       {
        textprintf_centre(backgr,font,x,y,108,"Keys are needed to activate crystals");
       }
     else if(n==12)
       {
        textprintf_centre(backgr,font,x,y,108,"Watch out for spikes, they hurt your player");
       }
     else if(n==13)
       {
        textprintf_centre(backgr,font,x,y,108,"Touch crystals (with enough keys) to beat the level");
        textprintf_centre(backgr,font,x,y+10,108,"Blue = 1 Key    Red = 2 Keys    Green = 3 keys");
       }
    }


void do_tut(void)   //calls all of the functions in order based on the
//games cycles done to play a tutorial
	{
     show_help=1;
     if(cycles>20 && cycles<30)
       {
        player.on_up();
        tutorial_message=1;
       }
     else if(cycles>60 && cycles<75)
       {
        player.on_down();
        tutorial_message=2;
       }
     else if(cycles>90 && cycles<100)
       {
        player.on_up();
       }
     else if(cycles>130 && cycles<146)
       {
        player.on_right();
        tutorial_message=4;
       }
     else if(cycles>170 && cycles<185)
       {
        player.on_left();
        tutorial_message=3;
       }
     else if(cycles>200 && cycles<205)
       {
        player.on_jump();
        tutorial_message=5;
       }
     else if(cycles>235 && cycles<250)
       {
        player.next_gun();
        tutorial_message=6;
       }
     else if(cycles>280 && cycles<285)
       {
        player.prev_gun();
        tutorial_message=7;
       }
     else if(cycles>290 && cycles<300)
       {
        player.on_right();
       }
     else if(cycles>315 && cycles<335)
       {
        player.fire();
        tutorial_message=8;
       }
     else if(cycles>360 && cycles<390)
       {
        player.on_right();
        tutorial_message=9;
       }
     else if(cycles>420 && cycles<438)
       {
        player.on_right();
        tutorial_message=10;
       }
     else if(cycles>438 && cycles<480)
       {
        player.fire();
       }
     else if(cycles>510 && cycles <525)
       {
        player.on_right();
        tutorial_message=11;
       }
     else if(cycles>550 && cycles<583)
       {
        player.on_right();
        tutorial_message=12;
       }
     else if(cycles>605 && cycles<620)
       {
        tutorial_message=13;
       }
     else if(cycles>635 && cycles<650)
       {
        player.on_right();
	   }
     else if(cycles>710)
       {
        key[KEY_ESC]=true;
       }
    }

void draw_sprite_centre(BITMAP *backgr, BITMAP *pic, int x, int y)
	{
     draw_sprite(backgr,pic,x-pic->w/2,y-pic->h/2);
    }

int main(void)
	{
     startup();
     seconds=0;
     cycles_done=0;
     cycles=0;
     sec=0;
     exit_game=0;
     play_game=0;

     while(exit_game==0)
       {
        fade=1;
        menu();
     	while(!key[KEY_ESC] && play_game==1)
       	  {
           //calculates the fps
       	   calc_fps();

           if (sec>cycles) //slows down the speed of the game logic to about
             //20 fps of game logic
             {
              cycles++;
              move_all();
             }

           //draws everything it whenever it can, but the player won't notice
           //any slow down above 20 fps.
           cycles_done++;
           draw_all();
         }
       }
	}
 END_OF_MAIN();



