#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include <iostream.h>
#include "allegro.h"
//#include "titans.h"
//#include "CMap9.h"
//#include "side_class.h"
/*#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include <iostream.h>
#include "allegro.h" */

fixed get_angle(float fx1,float fy1, float fx2, float fy2);
float get_dist(float x1,float y1,float x2,float y2);
fixed set_angle(fixed a, fixed angle);

fixed set_angle(fixed a, fixed angle)
	{
    //fixed angle;
    a=fixtoi(a);
    angle=fixtoi(angle);

    if(a>265)
      a-=256;
    else if(a<0)
      a+=256;
    if(angle>256)
      angle-=256;
    else if(angle<0)
      angle+=256;


    if(angle<a)
   	    angle++;
    else if(angle>a)
        angle--;

    return (itofix(angle));
    }

class CAnim
	{
     private:
        int number_of_frames;
        int frame;
        int rest;
        BITMAP *bmp[30];
	public:
    	void init(void);
        int draw_anim(BITMAP *backgr, int x, int y, int sprit, int going, int delay);
       // int draw_trans_anim((BITMAP *backgr, int x, int y, int going, int delay);
        void add_bmp(BITMAP *pic);
      	int get_frame(void);
        int get_w(void);
        int get_h(void);
        BITMAP* ret_frame(void);
        void set_frame(int n);
	};

void CAnim :: set_frame(int n)
	{
     frame=n;
    }

BITMAP * CAnim::ret_frame(void)
	{
     return bmp[frame];
    }

int CAnim::get_w(void)
	{
     return (bmp[frame]->w);
   	}
int CAnim::get_h(void)
	{
     return (bmp[frame]->h);
    }

void CAnim::init(void)
	{
     number_of_frames=-1;
     frame=0;
     rest=0;
    }

int CAnim::draw_anim(BITMAP *backgr, int x, int y, int sprit, int going, int delay)
	{
     int ret=0;
     if(sprit==1)
     	draw_sprite(backgr,bmp[frame],x,y);
     else if(sprit==0)
        blit(bmp[frame],backgr,x,y,0,0,bmp[frame]->w,bmp[frame]->h);
     else if(sprit==2)
        draw_trans_sprite(backgr,bmp[frame],x,y);

    if(rest<delay)
      rest++;
    else if(rest>=delay)
      rest=0;

    if(going==1 && rest==delay)
       {
     	frame++;
     	if(frame>number_of_frames)
          {
       		frame=0;
            ret=1000; //returns 1000 is it is at the end of the animation
           }
         else
           ret=frame; //otherwise it returns the frame number
       }
    return ret;
	}

void CAnim::add_bmp(BITMAP *pic)
	{
     if(number_of_frames<28)
       number_of_frames++;
     bmp[number_of_frames]=pic;
    }

int CAnim::get_frame(void)
	{
	return (frame);
	}

class CTile
	{
     private:
        //CAnim anim2;
        BITMAP *anim, *walk;
        int sx, sy;
        int no;

	public:
    	int w,h;
        short exist;	//0=false 1=true


        void init(void);
    	void load_tile(/*CAnim load_anim*/BITMAP *b, BITMAP *b_walk, int n);
     	void draw_tile(BITMAP *backgr, BITMAP *bmp_walk,int x, int y, int sprit, int an);
        void draw_tile(BITMAP *bmp_walk,int x, int y, int sprit, int an);
        void set_screen_pos(int x, int y);
        int get_screen_x(void);
        int get_screen_y(void);
        void draw_trans(BITMAP *backgr, int x, int y);
        int get_no(void);
        void set_no(int n);
        void draw_tile2(BITMAP *backgr, float x, float y);
	};

void CTile::draw_tile2(BITMAP *backgr, float x, float y)
	{
     draw_sprite(backgr,anim,(int)x,(int)y);
    }

void CTile::set_no(int n)
	{
     no=n;
    }

int CTile::get_no(void)
	{
     return no;
    }

void CTile::init(void)
	{
     exist=0;
     w=0;
     h=0;
     sx=0;
     sy=0;
    }

void CTile::set_screen_pos(int x, int y)
	{
     sx=x;
     sy=y;
    }

int CTile::get_screen_x(void)
	{
     return(sx);
    }

int CTile::get_screen_y(void)
	{
     return(sy);
    }

void CTile::load_tile(/*CAnim load_anim*/BITMAP *b, BITMAP *b_walk, int n)
	{
     exist=1;
     //anim=load_anim;
     anim=b;
     walk=b_walk;
     no=n;
    }

void CTile::draw_tile(BITMAP *backgr,BITMAP *bmp_walk, int x, int y, int sprit, int an)
	{
     //anim.draw_anim(backgr,x,y,sprit,an,10);
     draw_sprite(backgr,anim,x,y);
     draw_sprite(bmp_walk,walk,x,y);
    }

void CTile::draw_tile(BITMAP *bmp_walk, int x, int y, int sprit, int an)
	{
     //anim.draw_anim(backgr,x,y,sprit,an,10);
     //draw_sprite(backgr,anim,x,y);
     draw_sprite(bmp_walk,walk,x,y);
    }

void CTile::draw_trans(BITMAP *backgr, int x, int y)
	{
     //anim.draw_anim(backgr,x,y,sprit,an,10);
     //draw_sprite(backgr,anim,x,y);
     draw_trans_sprite(backgr,anim,x,y);
    }

class CLayer
	{
     private:
     	CTile tile[300][300];
        int layer_type;
        int layer_width, layer_heigth;
        int x, y;
        int tile_w, tile_h;
        int s_w, s_h;	           //screen width and height

	public:
    	void init(int l_t, int l_w, int l_h, int t_w, int t_h, int s_ww, int s_hh);
    	void draw_layer(BITMAP *backgr,BITMAP*bmp_walk, int bmp_x, int bmp_y,
                        int map_x, int map_y, int sprit, int an);
        void draw_layer(BITMAP*bmp_walk, int bmp_x, int bmp_y,
                        int map_x, int map_y, int sprit, int an);
        void load_tile(CTile t, int xx, int yy);

        int get_colour(float xx, float yy);

        void save_layer (FILE *fp);
        void load_layer (FILE *fp);
        int get_tile_no(int x, int y);
        int coll(float xx, float yy);
        void remove_tile(int xx, int yy);
	};

void CLayer::remove_tile(int xx, int yy)
	{
    tile[xx][yy].set_no(0);
    tile[xx][yy].exist=0;
    }

int CLayer::get_tile_no(int x, int y)
	{
     return tile[x][y].get_no();
    }

void CLayer::save_layer (FILE *fp)
	{
    // FILE *fp;
    // fp=fopen(name,"w");

     for(x=0;x<layer_width;x++)
        for(y=0;y<layer_heigth;y++)
        	{
            //fprintf(fp,"%d ",tile[no].type);
            //fprintf(fp,"%d ",tile[no].walk);

            fprintf(fp,"%d ",tile[x][y].get_no());
            //fprintf(fp,"%d ",tile[no].type3);
            //OutFile<<tile[x][y].get_no()<<endl;
        	}
       // fprintf(fp,"%d ",start_x);
       // fprintf(fp,"%d ",start_y);
     //fclose(fp);
     }

void CLayer::load_layer (FILE *fp)
	{
 	// FILE *fp;
    // fp=fopen(name,"r");
     int num;
     for(x=0;x<layer_width;x++)
        for(y=0;y<layer_heigth;y++)
        	{
             num=0;
             fscanf(fp,"%d",&num);
             tile[x][y].set_no(num);
            }

    fclose(fp);
    }


int CLayer::get_colour(float xx, float yy)
	{
     if(xx>0 && yy>0)
       {

     CTile temp;
     BITMAP *temp2;
     temp2=create_bitmap(32,32);
     rectfill(temp2,0,0,32,32,0);


     int x2=(int)xx/tile_w;
     int y2=(int)yy/tile_h;

     int c;

     if(tile[x2][y2].exist==1)
       {
     	temp=tile[x2][y2];

     	temp.draw_tile(temp2,0,0,0,0);

     	int x3=(int)xx%tile_w;
     	int y3=(int)yy%tile_h;

     	c=getpixel(temp2,x3,y3);
       }
     else
       c=0;

     destroy_bitmap(temp2);

     return c;
    }
   }

int CLayer::coll(float xx, float yy)
	{
     if(xx>0 && yy>0)
       {

     CTile temp;
     //BITMAP *temp2;
     //temp2=create_bitmap(32,32);
     //rectfill(temp2,0,0,32,32,0);


     int x2=(int)xx/tile_w;
     int y2=(int)yy/tile_h;

     if(tile[x2][y2].exist==1)
     	return(tile[x2][y2].get_no());
     else
       return -1;
    }

     /*int c;

     if(tile[x2][y2].exist==1)
       {
     	temp=tile[x2][y2];

     	temp.draw_tile(temp2,0,0,0,0);

     	int x3=(int)xx%tile_w;
     	int y3=(int)yy%tile_h;

     	c=getpixel(temp2,x3,y3);
       }
     else
       c=0;

     destroy_bitmap(temp2);

     return c;
     //putpixel(bmp,x3,y3,10);



    /* BITMAP *tempb=create_bitmap(tile_w,tile_h);
     temp.draw_tile(tempb,0,0,0,0);

     return (getpixel(tempb,x3,y3)); */

   }



void CLayer::init(int l_t, int l_w, int l_h, int t_w, int t_h, int s_ww, int s_hh)
	{
     int x,y;
     layer_type=l_t;
     layer_width=l_w;
     layer_heigth=l_h;
     tile_w=t_w;
     tile_h=t_h;
     s_w=s_ww;
     s_h=s_hh;
     for(y=0;y<300;y++)
        for(x=0;x<300;x++)
           tile[x][y].init();
    }


void CLayer::draw_layer(BITMAP *backgr, BITMAP *bmp_walk,int bmp_x, int bmp_y,
                        int map_x, int map_y, int sprit, int an)
	{
     int xx,yy,n,mx,my;

     mx=map_x/32;
     my=map_y/32;

     if(mx<0)
       mx=0;
     else if(mx+s_w/tile_w>layer_width)
       mx=layer_width;
     if(my<0)
       my=0;
     else if(my+s_h/tile_h>layer_heigth)
       my=layer_heigth;

	for(yy=my;yy<my+s_h/tile_h+2;yy++)
     	for(xx=mx; xx<mx+s_w/tile_w+2 ;xx++)
          {
           if( (xx*tile_w+tile_w>map_x && xx*tile_w/*-(tile_w*5)*/ <map_x+s_w) &&
               (yy*tile_h+tile_h>map_y && yy*tile_h-tile_h <map_y+s_h) )
             {
				if(tile[xx][yy].exist==1)
                  	{
           			tile[xx][yy].draw_tile(backgr,bmp_walk,
                                       	bmp_x+xx*tile_w-map_x,
                                       	bmp_y+yy*tile_h-map_y,
                                       	sprit,an);
                    tile[xx][yy].set_screen_pos(bmp_x+xx*tile_w-map_x,bmp_y+yy*tile_h-map_y);
                	}
              }
             else
             	tile[xx][yy].set_screen_pos(-1,-1);
          }

	}

void CLayer::draw_layer(BITMAP *bmp_walk,int bmp_x, int bmp_y,
                        int map_x, int map_y, int sprit, int an)
	{
     int xx,yy,n,mx,my;

     mx=map_x/32;
     my=map_y/32;

     if(mx<0)
       mx=0;
     else if(mx+s_w/tile_w>layer_width)
       mx=layer_width;
     if(my<0)
       my=0;
     else if(my+s_h/tile_h>layer_heigth)
       my=layer_heigth;

	for(yy=my;yy<my+s_h/tile_h+2;yy++)
     	for(xx=mx; xx<mx+s_w/tile_w+2 ;xx++)
          {
           if( (xx*tile_w+tile_w>map_x && xx*tile_w/*-(tile_w*5)*/ <map_x+s_w) &&
               (yy*tile_h+tile_h>map_y && yy*tile_h-tile_h <map_y+s_h) )
             {
				if(tile[xx][yy].exist==1)
                  	{
           			tile[xx][yy].draw_tile(bmp_walk,
                                       	bmp_x+xx*tile_w-map_x,
                                       	bmp_y+yy*tile_h-map_y,
                                       	sprit,an);
                    tile[xx][yy].set_screen_pos(bmp_x+xx*tile_w-map_x,bmp_y+yy*tile_h-map_y);
                	}
              }
             else
             	tile[xx][yy].set_screen_pos(-1,-1);
          }

	}

void CLayer::load_tile(CTile t, int xx, int yy)
	{
     tile[xx][yy]=t;
    }

fixed get_angle(float fx1,float fy1, float fx2, float fy2)
	{
    float x1=fx1,y1=fy1,x2=fx2,y2=fy2;

	fixed a;
	if (x1==x2)
		{
		if (y2<y1)
			a=itofix(192);
		else
			a=itofix(64);
		}
	else
		{
		a=fatan(ftofix(((float)(y2-y1)/(float)(x2-x1))));
		if ((x2-x1<=0) && ((y2-y1)<=0))
			a+=itofix(128);
		else if ((x2-x1<=0) && (y2-y1>=0))
			a+=itofix(128);
		if ((x2-x1>=0) && ((y2-y1)<=0))
			a=fadd(itofix(256),a);
		}
    a+=ftofix(90/1.40625);

	return a;
}

typedef struct proj_att
	{
     int damage;
     float speed;
     CAnim pic;
     float accel;
     int cool;
     int dist;
     int type;
    };

class CProj
	{
     public:
     	proj_att att;
     	float x,y;
        float m_x, m_y;
        fixed angle;
        int exist;
        float speed;
        int distance;

        void init(void);
        void init(float sx,float sy, fixed sangle,
                  int s_exist, float s_speed, proj_att satt);
        void draw_proj(BITMAP *backgr, float screen_x, float screen_y, int move,
                       float o_x, float o_y);
        void move_proj(float o_x, float o_y);
        void set_angle(fixed a, int how);
	};

void CProj::set_angle(fixed a, int how)//how 0=instant, 1=real
	{
     if(how==0)
     	angle=a;
     else if(how==1)
       {
        if(fixtoi(a)>fixtoi(angle))
          angle-=fixtoi(2);
        else if(fixtoi(a)<fixtoi(angle))
          angle+=fixtoi(2);
       }
     m_y = -cos( (fixtoi(angle)*1.40625) *M_PI/180);
	 m_x = sin( (fixtoi(angle)*1.40625) *M_PI/180);
    }

void CProj::draw_proj(BITMAP *backgr, float screen_x, float screen_y, int move,
                      float o_x, float o_y)
	{
     BITMAP *temp;
     //if(x-screen_x>1000 || x-screen_x<-1000 || y-screen_y>1000 || y-screen_y<-1000)
     //  exist=0;
     if(distance>=att.dist)
       {
        //explode
       exist=0;
       }

     if(move==1)
     	move_proj(o_x,o_y);

     temp=create_bitmap(att.pic.get_w(),
                        att.pic.get_h());
     att.pic.draw_anim(temp,0,0,0,1,1);

     rotate_sprite(backgr,temp,(int)x-(int)screen_x,(int)y-(int)screen_y,angle);
     destroy_bitmap(temp);
    }

void CProj::move_proj(float o_x,float o_y)
	{
     x+=m_x*speed;
     y+=m_y*speed;

     distance++;

     if(speed<att.speed)
       speed+=att.accel;
     else if(speed>att.speed)
       speed--;

     if(att.type==1)
       {
     	set_angle(angle+itofix(10),0);
        x+=o_x;
        y+=o_y;
       }
    }

void CProj::init(void)
	{
     x=0;
     y=0;
     m_x=0;
     m_y=0;
     exist=0;
     angle=(itofix(0));
     speed=0;
    }

void CProj::init(float sx, float sy, fixed sangle,
                 int s_exist, float s_speed, proj_att satt)
	{
     x=sx;
     y=sy;
     angle=sangle;
     distance=0;

     m_y = -cos( (fixtoi(angle)*1.40625) *M_PI/180);
	 m_x = sin( (fixtoi(angle)*1.40625) *M_PI/180);
	 exist=s_exist;

     speed=s_speed;
     att=satt;
    }

class CProjSet
	{
     private:
		CProj proj[100];
        int num;
        int cool;
	public:
    	void init(void);
        void fire_proj(float x, float y, fixed angle,proj_att att, float s_speed);
        void draw_proj(BITMAP *backgr, int screen_x, int screen_y, int move, float o_x, float o_y);
	};


void CProjSet::draw_proj(BITMAP *backgr, int screen_x, int screen_y, int move, float o_x, float o_y)
	{
     if(cool>0 && move==1)
       cool--;
     for(int n=0;n<100;n++)
        if(proj[n].exist==1)
          proj[n].draw_proj(backgr,screen_x,screen_y, move, o_x, o_y);
	}

void CProjSet::fire_proj(float player_x, float player_y, fixed angle, proj_att att, float s_speed)
	{
     if(cool==0)
       {
     	proj[num].init(player_x,player_y,angle,1,s_speed,att);
     	cool=att.cool;
     	num++;
     	if(num>98)
       		num=0;
       }
	}

void CProjSet::init(void)
	{
     num=0;
     for(int n=0;n<100;n++)
        proj[n].exist=0;
    }

float get_dist(float x1,float y1,float x2,float y2)
	{
     float tx,ty,td;
     tx=x1-x2;
     ty=y1-y2;
     tx*=tx;
     ty*=ty;
     tx+=ty;
     td=sqrt(tx);
     return(td);
    }





