//this class is for an object (player or enemy)
//it handles moving, drawing, firing, and aiming for the player
class object
	{
     protected:
     	float x,y; //position of the player
        float screen_x,screen_y; //postion of the screen on the real world map
        float y_speed,x_speed; //current speed in each direction
        BITMAP *pic;   //picture for the player
        BITMAP *pic_jump;
        BITMAP *arm_pic;
        BITMAP *crouch_pic;
        
        float scroll_speed;

	    float offset;
	    short int d;

        BITMAP *current_pic;
        int wep;     //current weapons selected
        att_set att; //it's attributes that define how it will behave
        int number_of_weapons;	//total number of weapons
        int jumped;     //flag: 1=jumped 0=not jumped
        int dir;        //direction player is facing (1=right 2=left)
        projectile proj[50];  //up to 50 projectiles
        int p_num;      //number for next projectile to be fired

        float p_x,p_y,p_x2,p_y2;
        part_set parts;

        int ammo[3];
        int switch_gun_count;  //a counter to prevent player from switching
        //guns too fast
        float arm_length;

        int crouch_flag;  //1 is crouching, 0 is standing
        int crouch_wait_count;

	public:
        int life;
        weapon gun[20]; //aresnal of up to 20 different weapons
    	//initalizes player with given picture attribute set and postion
    	void init(BITMAP * ppic,BITMAP *ppic_jump,BITMAP *aarm, BITMAP *crouchp, att_set a, float xx, float yy);
        //draw on backgr in realtion to s_x, s_y
    	void draw(BITMAP *backgr, float s_x, float s_y);

        //return screen postion for this player
        float get_sx(void);
        float get_sy(void);

        //functions called on different key presses
        void on_right(void);
        void on_left(void);
        void on_up(void);
        void on_down(void);

        //move the character using it's x and y speed
        int move(CLayer *main_layer);

        //decrease speeds of player
        void friction(void);

        //checks to see if the player can move down, and adjust y speed
        //appropratily
        //returns the number of tile he's standing on also
        int move_down(CLayer *main_layer);
        void move_up(CLayer *main_layer);

        //same as move_down, but for left and right
        int move_right(CLayer *main_layer);
        int move_left(CLayer *main_layer);

        //called when the player hits the jump key
	    void on_jump(void);

        //draws gun on backgr in realtion to s_x, s_y
        void draw_gun(BITMAP *backgr, float s_x, float s_y);
        //adds a new gun to the player's arsenal
        void add_gun(weapon w);

        //clears all guns from the player
        void clear_guns(void);

        //fires the gun
        void fire(void);
        //moves all the projectiles
        void move_proj(CLayer *main_layer);
        void draw_proj(BITMAP *backgr, float s_x, float s_y);

        //checks to see if any of this object's projectile hit the object p
        int check_proj_col(object *p);

        //writes the current weapon's name at xx,yy
        void write_wep_name(BITMAP *backgr, int xx, int yy, FONT *f);

        //returns the object's current x and y position
        float ret_y(void);
        float ret_x(void);

        //return a pointer to the object's picture
        BITMAP* ret_pic(void);

        //switches gun
        void prev_gun(void);
        void next_gun(void);

        float ret_p_x(void);
        float ret_p_y(void);
        float ret_p_x2(void);
        float ret_p_y2(void);

        void destroy_proj(void);
        void set_arm_length(float n);
        void check_expl_hit(explosion_set *expl);

        void toggle_crouch(void);
        
        void not_up_or_down(void);
        
        void set_scroll_speed(float s);
     };

void object::set_scroll_speed(float s)
{
    scroll_speed=s;
}

void object::toggle_crouch(void)
	{
     if(crouch_flag==0 && crouch_wait_count==0 && jumped==0)
       {
       crouch_flag=1;
       crouch_wait_count=10;
       y+=23;
       current_pic = crouch_pic;
       }
     else if(crouch_flag==1 && crouch_wait_count==0 && jumped==0)
       {
        crouch_flag=0;
        crouch_wait_count=10;
        y-=46;
       // on_jump();
        y_speed=-11;
        current_pic= pic;
       }
     }

void object::check_expl_hit(explosion_set *expl)
	{
     int ret=-1;
     ret=expl->check_col(pic,x,y);
     if(ret!=-1)
       {
        life-=expl->ret_damage(ret);
       }
     }

void object::set_arm_length(float n)
	{
     arm_length=n;
    }

void object::destroy_proj(void)
     {
      for(int n=0 ; n<50 ; n++)
         {
         proj[n].not_fired(0);
         }
     }

float object::ret_p_x(void)
      {
      return p_x;
      }
      
float object::ret_p_y(void)
      {
      return p_y;
      }

float object::ret_p_x2(void)
      {
      return p_x2;
      }
      
float object::ret_p_y2(void)
      {
      return p_y2;
      }


void object::prev_gun(void)
	{
     if(switch_gun_count==0)  //counter to stop player from switching guns
       //too fast. It is decreased by one every loop in the function object::move
      {
      wep--;   //go to previous weapon
      switch_gun_count=8;//set counter to wait 8 loops before player can
      //change guns again
      while(gun[wep].send_ammo()==0) //while the next gun has no ammo
        {
         wep--;//go to the next one up the list.
         if(wep<0) //if go before the first weapon
           wep=number_of_weapons;//go to the last weapon
        }
      }
    }

void object::next_gun(void)   //same as prev_gun
	{
     if(switch_gun_count==0)
      {
      wep++;
      switch_gun_count=8;
      while(gun[wep].send_ammo()==0)
        {
        wep++;
        if(wep>number_of_weapons)
          wep=0;
       }
      }
    }

BITMAP* object::ret_pic(void)
	{
     return current_pic;
    }

float object::ret_x(void)
	{
     return x;
    }
float object::ret_y(void)
	{
     return y;
    }

int object::check_proj_col(object *p)
	{
     int ret=0; //default return value is zero

     for(int n=0 ; n<50 ;n++) //goes through all projectiles
        {
         //checks to see if the current projectile in in contact with
         //the the object's picture at it's position x,y.
         if(proj[n].check_coll(p->x , p->y , p->current_pic)==1)
           {
            //if they are hitting
            ret=proj[n].get_damage(); //return amount of damage done
            proj[n].not_fired(1); 	//the projectile is not fired anymore
            break;
           }
         else
           ret=0;
        }
     return ret;
     }

void object::write_wep_name(BITMAP *backgr, int xx, int yy, FONT* f)
	{
     gun[wep].write_name(backgr,xx,yy,136,f);
    }

void object::move_proj(CLayer *main_layer)
	{
     //goes through all 200
     for (int n=0 ; n<50 ; n++)
        proj[n].move(main_layer); //moves them
    }

void object::draw_proj(BITMAP *backgr, float s_x, float s_y)
	{
     //goes through all 200
     for(int n=0 ; n<50 ;n++)
        proj[n].draw(backgr, s_x, s_y);//draws them in relation to s_x, s_y
    }

void object::fire(void)
	{
     //calls fire function from current gun passing it a pointer to the
     //next projectile. Will only shoot is it has enough ammo, and it's
     //cooldown is ready
     //an ammo of -1 means it is unlimited
     if( (gun[wep].send_ammo() > 0 || gun[wep].send_ammo()==-1) && gun[wep].send_cool()<=0)
        {
         if(gun[wep].send_ammo()!=-1)//do not decrease ammo if it is unlimited
         	gun[wep].set_ammo(gun[wep].send_ammo()-1);

     	 gun[wep].fire(&proj[p_num] , &parts);

     	 //adjucts player's speed because of recoil
     	 x_speed-=gun[wep].send_dx() * proj[p_num].send_recoil();
     	 y_speed-=gun[wep].send_dy() * proj[p_num].send_recoil();

     	 //move to next projectile
     	 p_num++;
     	 if(p_num>48)
       	    p_num=0;
        }
    }

void object::clear_guns(void)
	{
     number_of_weapons=0;
     for(int n=0 ; n<20 ; n++)
        {
         gun[n].set_ammo(0);
        }
     }

void object::add_gun(weapon w)
	{
     if(number_of_weapons<19) //if under the maximum weapons
       {
       number_of_weapons++;
       gun[number_of_weapons]=w;
       }
    }

void object::draw_gun(BITMAP *backgr, float s_x, float s_y)
	{
     gun[wep].draw(backgr,arm_pic,s_x,s_y+(int)(5+offset),x,y);
    }

void object::init(BITMAP * ppic, BITMAP *ppic_jump,BITMAP *aarm,BITMAP *crouchp, att_set a, float xx, float yy)
	{
     crouch_wait_count=0;
     crouch_flag=0;
     crouch_pic=crouchp;
     p_x=0;
     p_y=0;
     p_x2=0;
     p_y2=0;
     arm_length=0;
     pic = ppic;
     pic_jump=ppic_jump;
     arm_pic=aarm;
     x=xx;
     y=yy;

    scroll_speed=1;

     //sets inital screen_x and screen_y so that player is in the middle
     screen_x=xx-320;
     screen_y=yy-240;
	 att=a;
     x_speed=0;
     y_speed=0;
     jumped=1;
     number_of_weapons=0;
     wep=number_of_weapons+1;
     dir=1;
     for(int n=0; n<50 ;n++)
        proj[n].init();
     p_num=0;
     parts.init();
     switch_gun_count=0;
     //ammo[0]=ammo1;
     //ammo[1]=ammo2;
     current_pic=pic;
     
     offset=-2;
	 d=1;
     
    }

void object::draw(BITMAP *backgr, float s_x, float s_y)
	{

	 
     if(y_speed<0)
        {        
        if(dir==1)
     	   draw_sprite(backgr,pic_jump,(int)x-(int)s_x,(int)y-(int)s_y-(int)(5+offset));
        else if(dir==2)
           draw_sprite_h_flip(backgr,pic_jump,(int)x-(int)s_x,(int)y-(int)s_y-(int)(5+offset));
        }
     else
        {
        if(dir==1)
     	   draw_sprite(backgr,current_pic,(int)x-(int)s_x,(int)y-(int)s_y-(int)(5+offset));
        else if(dir==2)
           draw_sprite_h_flip(backgr,current_pic,(int)x-(int)s_x,(int)y-(int)s_y-(int)(5+offset));
        }
          
    

     parts.draw_all(backgr,s_x,s_y);
    }

float object::get_sx(void)
	{
     return screen_x;
	}
float object::get_sy(void)
	{
     return screen_y;
    }

void object::on_right(void)
	{
     if(x_speed>=0)
     	dir=1;
     if(x_speed<att.max_speed && crouch_flag==0)
        x_speed+=att.accel;
    }

void object::on_left(void)
	{
     if(x_speed<=0)
     	dir=2;
     if(x_speed>-att.max_speed && crouch_flag==0)
     	x_speed-=att.accel;
    }

void object::on_up(void)
	{
    gun[wep].up();
    }
void object::on_down(void)
	{
    gun[wep].down();
    }
    
void object::not_up_or_down(void)
    {
    gun[wep].norm();
    }

void object::friction(void)
	{
     if(x_speed>=friction_def)
       x_speed-=friction_def;
     else if(x_speed>0 && x_speed <friction_def)
       x_speed=0;

     if(x_speed<=-friction_def)
       x_speed+=friction_def;
     else if(x_speed<0 && x_speed >-friction_def)
       x_speed=0;
   }

int object::move(CLayer *main_layer)
	{
     int ret=0;
     if(jumped==1)
        move_up(main_layer);

     if(move_down(main_layer)==9)    //makes player fall
        //if he's standing on tile 9 they are spikes, so he should loose life
        {
        life-=80;
        y_speed=-25;
        }


      //the function move_left and move_right will return a 1 if they
      //hit something, otherwise they will return zero
      if(ret==0)
      	ret=move_right(main_layer);   //checks to see if it can move right
      if(ret==0)
      	ret=move_left(main_layer);	//checks to see if it can move left

      //move the object
      y+=y_speed;
      x+=x_speed;

     // if(x_speed>0)	         //moving right
      //  {
         //if(x-screen_x>=320)   //scroll screen only if player is in the middle
        //   {
           screen_x+=scroll_speed;
           p_x+=scroll_speed/5;
           p_x2+=scroll_speed/3;
         //  }
      //  }
    //  else if(x_speed<0)      //moving left
   //     {
       /*  if(screen_x>0)       //do not scroll screen off of the edge
           {
           screen_x+=x_speed;
           p_x+=x_speed/5;
           p_x2+=x_speed/3;
           }*/
     //   }

      if(y_speed>0)	         //moving down
        {
         if(y-screen_y>=240)
           {
           screen_y+=y_speed;
           }
        }
      else if(y_speed<0)     //moving up
        {
         if(screen_y>0)
          {
           screen_y+=y_speed;
          }
        }

      gun[wep].update(dir,x+current_pic->w/2,y);

      parts.move_all(1);

      //count down timer to allow player to change guns again
      if(switch_gun_count>0)
      	switch_gun_count--;
      if(crouch_wait_count>0)
        crouch_wait_count--;

     //the offset for adding the effect of hovering to the object
     offset+=.55*d;
     
     if(screen_x>x+25)
        life-=1000;
     
     if(offset<-4)
        d=1;
     else if(offset>4)
        d=-1; 

      return ret;
     }

int object::move_down(CLayer *main_layer)
	{
     int s_posx, s_posy;
     int xx,yy;
     int hit=0;
     int dist=0;
     int ret=-1;

     s_posx = (int)x;
     s_posy = (int)y;

     if(y_speed < att.term_vel)
        	y_speed+=gravity;   //increase speed

     for(yy=s_posy+current_pic->h ; yy<s_posy+current_pic->h+y_speed+1 ; yy++)
        {

         for(xx=s_posx+1 ; xx<s_posx + current_pic->w ; xx++)
            {
            //if hit ground
            if(main_layer->coll(xx,yy)!=-1)
               {
                y_speed=dist;   //set speed to move the right amount to the ground
                hit=1;          //set flag to tell you have hit the ground
                ret=main_layer->coll(xx,yy);  //return the tile standing on
                break;
       			}
            }
         dist++;   //increase distance travelled
         }

     if(hit==1)  //if you hit the ground
       jumped=0;  //reset flag to allow jumping

     if(hit==0)   //if didn't hit ground
       {
        jumped=1;  //can't jump
  //      if(y_speed < att.term_vel)
   //     	y_speed+=gravity;   //increase speed
       }
   return ret;
    }

void object::move_up(CLayer *main_layer)
	{
     int s_posx, s_posy;
     int xx,yy;
     int hit=0;
     int dist=0;

     s_posx = (int)x;
     s_posy = (int)y;

     for(yy=s_posy ; yy>s_posy+y_speed-1 ; yy--)
        {

         for(xx=s_posx+1 ; xx<s_posx + current_pic->w ; xx++)
            {
            //if(main_layer->get_colour(xx,yy)!=0)  //if hit ground
            if(main_layer->coll(xx,yy)!=-1)
               {
                y_speed=dist;   //set speed to move the right amount to the ground
                hit=1;          //set flag to tell you have hit the ground
                break;
       			}
            }
         dist++;   //increase distance travelled
         }
    }

int object::move_right(CLayer *main_layer)
	{
     int s_posx, s_posy;
     int xx,yy;
     int hit=0;
     int dist=0;
     int ret=0;

     s_posx = (int)x/*-(int)screen_x*/;
     s_posy = (int)y/*-(int)screen_y*/;

    if(screen_x>=x)
        {
        if(x_speed<-2)
            x_speed=0;
        x_speed+=scroll_speed;
        }

     for(xx=s_posx+current_pic->w ; xx < s_posx+current_pic->w+x_speed+1 ; xx++)
        {
         for(yy=s_posy ; yy<s_posy+current_pic->h ; yy++)
            {
             //if (getpixel(check,xx,yy)!=0)//if hit ground
             //if(main_layer->get_colour(xx,yy)!=0)
             if(main_layer->coll(xx,yy)!=-1)
       			{
                x_speed=dist;   //set speed to move the right amount to the ground
                hit=1;          //set flag to tell you have hit the ground
                ret=1;          //set return value to say it hit something
                break;
       			}
            }
         dist++;   //increase distance travelled
         }
        return ret;
        

	}

int object::move_left(CLayer *main_layer)
	{
     int s_posx, s_posy;
     int xx,yy;
     int hit=0;
     int dist=0;
     int ret=0;

     s_posx = (int)x;
     s_posy = (int)y;

     for(xx=s_posx ; xx > s_posx+x_speed ; xx--)
        {
         for(yy=s_posy ; yy<s_posy+current_pic->h ; yy++)
            {
             //if (getpixel(check,xx,yy)!=0)//if hit ground
             //if(main_layer->get_colour(xx,yy)!=0)
             if(main_layer->coll(xx,yy)!=-1)
       			{
                x_speed=-dist;   //set speed to move the right amount to the ground
                hit=1;          //set flag to tell you have hit the ground
                ret=1;
                break;
       			}
            }
         dist++;   //increase distance travelled
         }
      return ret;
	}

void object:: on_jump(void)
	{
     if(jumped==0)
       {
     	y_speed=-att.j_speed;
     	jumped=1;
       }
    }
