#include "string.h"
#include "CMapObject.h"
#include "rotk2.h"

class CObjectSet;

void CMapObject::load_script(char *filename)
{
    script.load_script(filename);
    has_script=true;
}

void CMapObject::set_up_pivot(Point pivot)
{
    float tx=x;
    pivot_point = pivot;



    if(y> pivot_point.y+5)
    {
        //length = get_dist(x,pivot.x,y,pivot.y);
        //length=40;

        length =sqrt((pivot.x-x)*(pivot.x-x) + (pivot.y-y)*(pivot.y-y));

       // textprintf(screen,font,5,200,makecol(255,0,0),"%f %f %f %f %f",x,pivot.x,y,pivot.y,length);
       // while(!key[KEY_Z]) {};

        angle2 = atan2(  y-pivot_point.y ,  x-pivot_point.x ) /*- M_PI/2*/ ;


        if(angle2>0)
            angle2 = M_PI/2 - angle2;
        if(angle2<0)
            angle2 = M_PI/2 + angle2;

        angle2+=M_PI;

        if(x<pivot_point.x)
            angle2-=M_PI/2;

        //temperary
        angle_vel=0;
        angle_acc=0;

        swinging=true;
    }

    //x=tx;

}

void CMapObject::consume(void)
{
    consumed=true;
    
    if(obInfo.consumed_wav!=-1)
    {
        play_sample((SAMPLE*)data[sound00+obInfo.consumed_wav].dat,100,125,1000,FALSE); 
    }
    
    /*if(consumed_wav)
        play_sample(consumed_wav,100,125,1000,FALSE);    
        
    if(playing_ambient==true)
        stop_sample(ambient_wav);*/
    
    //play_sample((SAMPLE*)data[click].dat,100,125,1000,FALSE);

}

int CMapObject::check_col_with_object(CMapObject *ob, CParts *parts,CDialog *dialog)
{
    int ret=-1;

    if(exist==true && consumed==false && curpic && ob->curpic && ob->exist)
    {
        //if(check_col_with_bitmap(pic,ob->pic,x,y,ob->x,ob->y) ==1)  //touching
        if(check_col_with_bitmap(iWidth,iHeight,ob->iWidth,ob->iHeight,x,y,ob->x,ob->y) ==true)  //touching
        //if(check_col_with_bbox((int)ob->x,(int)ob->y,(int)x+ob->iWidth,(int)y+pic->h)==true)  //touching
        {
            ret = 1;               
        }
    }   
    if(has_script)
        script.check_condition(this,ob,parts,dialog,ingameCin);

    return ret;
}

void CMapObject::set_anim(char *filename)
{
    anim.init();
    anim.create(filename);
    picture_type=USEANIM;
    curpic=anim.return_current_frame();
    iWidth=anim.ret_first_w();
    iHeight=anim.ret_first_h();
}


void CMapObject::toggle_anim(void)
{
    /*if(anim_on==true)
        anim_on=false;
    else if(anim_on==false)
        anim_on=true; */
}

void CMapObject::display_info(BITMAP *backgr, int x, int y, FONT *f)
{
   /* textprintf(backgr,f,x,y,makecol(0,255,0),"%d ",type);
    textprintf(backgr,f,x,y+15,makecol(0,255,0),"%d ",pickup_type);
    textprintf(backgr,f,x,y+30,makecol(0,255,0),"%s ",anim_file);   */
}

void CMapObject::enter_edit_mode(void)
{
    if(exist==true)
    {
        x=p1.x;
        y=p1.y;
        dx=0;
        dy=0;
        set_up_points();
        finalize_movement();
        consumed=false;
        if(obInfo.enim_type==2 || obInfo.enim_type==5)   //a falling rock or swooping enemy
            still=true;
    }
}

int CMapObject::check_col_with_point2(float px, float py)
{
    int ret=-1; //return -1 if there is no collision

    if(exist==true && curpic)
        {
        if( px>=p2.x && px<=p2.x+iWidth && py>=p2.y && py<=p2.y+iHeight )
            //ret=1;   //colliding with p2
            ret= 1;
        }

   return ret;
   // return ret;

}

void CMapObject::finalize_movement(void)  //this sets up everything for the object
{
    set_up_points();  //set up the movement points so that p1 is to the left of p2
    //find the angle that the platform needs to move at
    angle=atan2(p2.y-p1.y , p2.x-p1.x);
    //set it to the proper angle
    set_angle(angle,speed);

    //move the platform to one step away from its starting point
    x=p1.x;
    y=p1.y;
    x+=dx;
    y+=dy;
}

void CMapObject::move_to(float _x, float _y)  //moves the actual object
{
    x=_x;
    y=_y;
    p1.x=x;
    p1.y=y;

    if(obInfo.moving==false) //it is not a moving platform and it is not an enemy
    {
        //so make sure that both movement points are the same
        p2.x=x;
        p2.y=y;
    }
}

void CMapObject::move_to2(float _x, float _y)  //moves ther object's second movement point
{
    if(obInfo.moving==false)   //if it is stationary
    {
        move_to(_x,_y);  //move the actual object as well as the movement point
    }
    else     //otherwise it is a moving platform or object
    {
        //move just the second movement point
        p2.x=_x;
        p2.y=_y;
    }
}

void CMapObject::set_p2(Point p)
{
    p2=p;
}

void CMapObject::set_up_points(void)
{
    Point temp;

    if(p1.x > p2.x)
    {
        temp = p2;
        p2=p1;
        p1=temp;
        x=p1.x;
        y=p1.y;
   }

    /*if(obInfo.grav==true) //if the object reacts to gravity
        {
        p2.y=y;     //make sure its moving on the same horizontal plane
        }    */
}

void CMapObject::set_angle(float a, float s)
{
    angle=a;
    dx = cos(angle);
   //only set up the y component of the movement is the object is not affected by gravity
    if(obInfo.grav==false)
    {
        dy = sin(angle);
        y+=dy;
    }

    speed = s;

    x+=dx;

    /*if(obInfo.enim_type!=-1)    //it is an enemy
    {
        dx = dx*speed;

        if(obInfo.grav==false) //only adjust the y component if it doesn't regard gravity
            dy = dy*speed;
    }*/

}

int CMapObject::check_col_with_point(float px, float py)
{
    int ret=-1; //return -1 if there is no collision

    if(exist==true && curpic)
    {
        //if( px>=x && px<=x+pic->w && py>=y && py<=y+pic->h )
        //    ret= 1;
        
        if( px>=x && px<=x+iWidth && py>y && py<=y+iHeight)
            ret=1;
    }


    return ret;
}

void CMapObject::move_mo(void)
{
    if(exist==true && curpic)
    {
        if(y<0)
        {
            y=0;
            dy=0;
        }
    
        if(obInfo.moving==true && obInfo.type!=0 /*not the player*/ /*obInfo.grav==false*/)     //a moving platoform
        {
            if(obInfo.enim_type!=5)
                move_platform();
        }

        if(swinging==true)
        {
            move_swinging();
        }


        if(dx>0)
        {
            dir=RIGHT;
        }
        else if(dx<0)
        {
            dir=LEFT;
        }

        if(picture_type==USEANIM /*&& anim_on==true*/ )
        {
            move_anim();
        }
    }
}

int CMapObject::move_anim(void)
{
    int ret;
    ret = anim.move();
    curpic=anim.return_current_frame();  
    
    return ret;
}    

void CMapObject::move_swinging(void)
{
     float tx,ty;

    if(angle2>M_PI*2)
        angle2-=M_PI*2;
    else if(angle2<0)
        angle2+=M_PI*2;

    angle_acc = (gravity/length)*sin(angle2);

    angle_vel+=angle_acc*5;

    angle2+= angle_vel;

    tx = sin(angle2+M_PI)*length + pivot_point.x;
    ty = cos(angle2+M_PI)*length + pivot_point.y;

    dx = tx-x;
    dy = ty-y;

    angle_vel*=.995;

}

void CMapObject::move_platform(void)
{
    float old_angle=angle;
    static bool before=false;
    if(exist==true /*&& offscreen==false*/)
    {

        if(obInfo.enim_type!=-1)    //it is an enemy
            speed = obInfo.pickup_value;

        //if it is past either of its two horizontal movement points, turn it around
        if( ( (x > p2.x && dx>=0) || (x < p1.x && dx<=0) ) && speed>0)
        {
            angle+=M_PI;
            //dx*=-1;
        }

        //if it's moving only in the vertical directions it takes a bit more work
        //it see when it needs to be turned around
        else if(obInfo.grav==false)
        {
            if(p1.y < p2.y)
            {
                if(y<p1.y)
                    angle+=M_PI;
                else if(y>p2.y)
                    angle+=M_PI;
            }
            else if(p2.y < p1.y)
            {
                if(y>p1.y)
                    angle+=M_PI;
                else if(y<p2.y)
                    angle+=M_PI;
            }
        }

        //if the angle is bigger than 360 degrees, adjust for it
        if(angle>2*M_PI)
            angle-=2*M_PI;


        if(angle!=old_angle)   //if the angle changed
        {
            set_angle(angle,speed);
        }

        if((int)p1.x==(int)p2.x)
        {
            dx=0;
        }

        if(/*obInfo.enim_type==-1*/obInfo.grav==false)  //if it is not an enemy
        {
            //set up everything for the new angle
            //move the object one step this frame
            x+=dx*speed;

            if(obInfo.grav==false)
                y+=dy*speed;
        }
    }
}

void CMapObject::draw(BITMAP *backgr, int s_x, int s_y)
{
    if(exist==true && consumed==false && curpic && y>=-10 && x>=-10)
    {
        if(DEBUG==1)
            rect(backgr,(int)ceil((int)x-s_x),(int)ceil((int)y-s_y),(int)ceil((int)x-s_x)+iWidth,(int)ceil((int)y-s_y)+iHeight,makecol(0,255,0));

//        x-= (curpic->w -iWidth )/2;
    
        

        //if the object is swinging
        if(swinging==true)
        {
            //draw the line representing the rope/wen
            line(backgr,(int)(x+curpic->w/2-s_x),(int)(y+curpic->w/2-s_y),(int)(pivot_point.x-s_x),(int)(pivot_point.y-s_y),makecol(160,160,160));
        }

        //the invinc counter stops the object from being drawn on alternate frames
        //to make it flash
        if(invinc_counter%4 ==0 || invinc_counter%4 ==1 || invinc_counter%4 ==2)
        {

            //draw the object facing the correct direction
            if( ((dir==LEFT)))
            {
                if(x-s_x>=-curpic->w && y-s_y>=-curpic->h)
                {
                    draw_sprite_h_flip(backgr,curpic,(int)ceil((x-s_x)),(int)ceil((y-s_y)));
                }
            }
                
            else if( (dir==RIGHT  || obInfo.moving==false))
            {
                if(x-s_x>=-curpic->w && y-s_y>=-curpic->h)
                {
                    draw_sprite(backgr,curpic,(int)ceil((x-s_x)),(int)ceil((y-s_y)));
                }
            }
        }

        if(obInfo.moving==true && obInfo.tile_type==2)   //it's a moving platform
        {
            //draw a line between it's movement points
            //line(backgr,(int)((p1.x+.x+pic->w)/2-s_x),(int)((p1.y+p1.y+pic->h)/2-s_y),
            //(int)((p2.x+p2.x+pic->w)/2-s_x),(int)((p2.y+p2.y+pic->h)/2-s_y),makecol(0,150,0));
        }
        
//        x+= (curpic->w -iWidth )/2;
    }

}

void CMapObject::draw_trans(BITMAP *backgr, int s_x, int s_y)
{
    if(exist==true && curpic)
    {
    //x-= (curpic->w -iWidth )/2;
        //if(x-s_x+pic->w >0 && y-s_y+pic->h >0 && x<backgr->w && y<backgr->h)
                if(strcmp(obInfo.script_name,"none")!=0)    //it has a script print the name of the script
            textprintf_ex(backgr,font,(int)(x-s_x),(int)(y-s_y)-10,makecol(255,255,255),-1,"%s",obInfo.script_name);
            draw_trans_sprite(backgr,curpic,(int)(x-s_x),(int)(y-s_y));
    //x+= (curpic->w -iWidth )/2;
    }
}

void CMapObject::draw_preview(BITMAP *backgr, int s_x, int s_y)
{
    if(picture_type==USEANIM)
        curpic = anim.return_frame(0);
    
    if(exist==true && curpic)
    {

    /*x-= (curpic->w -iWidth )/2;
    p1.x-= (curpic->w -iWidth )/2;
    p2.x-= (curpic->w -iWidth )/2;*/

        if(strcmp(obInfo.script_name,"none")!=0)    //it has a script print the name of the script
            textprintf_ex(backgr,font,(int)(x-s_x),(int)(y-s_y)-10,makecol(255,255,255),-1,"%s",obInfo.script_name);
        // if(x-s_x+pic->w >0 && y-s_y+pic->h >0 && x<backgr->w && y<backgr->h)
        draw_sprite(backgr,curpic,(int)(x-s_x),(int)(y-s_y));


        //draws a rectangle around the first movement point (the standard position)
        rect(backgr,(int)(p2.x-s_x),(int)(p2.y-s_y),(int)(p2.x-s_x)+curpic->w,(int)(p2.y-s_y)+curpic->h,makecol(200,0,200));
        rect(backgr,(int)(p2.x-s_x)+1,(int)(p2.y-s_y)+1,(int)(p2.x-s_x)+curpic->w-1,(int)(p2.y-s_y)+curpic->h-1,makecol(200,0,200));

        //draws a rectangle around the second movement point (for moving platforms or enemies)
        rect(backgr,(int)(p1.x-s_x),(int)(p1.y-s_y),(int)(p1.x-s_x)+curpic->w,(int)(p1.y-s_y)+curpic->h,makecol(200,0,200));
        rect(backgr,(int)(p1.x-s_x)+1,(int)(p1.y-s_y)+1,(int)(p1.x-s_x)+curpic->w-1,(int)(p1.y-s_y)+curpic->h-1,makecol(200,0,200));

        //draws a line between the two movement point
        line(backgr,(int)((p1.x+p1.x+curpic->w)/2-s_x),(int)((p1.y+p1.y+curpic->h)/2-s_y),
                    (int)((p2.x+p2.x+curpic->w)/2-s_x),(int)((p2.y+p2.y+curpic->h)/2-s_y),
                    makecol(0,150,0));

               
    /*x+= (curpic->w -iWidth )/2;
    p1.x+= (curpic->w -iWidth )/2;
    p2.x+= (curpic->w -iWidth )/2;*/

    }
}

bool CMapObject::check_col_with_bbox(int x1,int y1, int x2, int y2)
{
    bool ret=false;
    
/*   
    if(x1 + w1 >= x2 && x1 <= x2 + w2 && 
       y1 + h1 >= y2 && y1 <= y2 + h2)
        return true;*/
    if(exist==true && curpic)
    {
        if(x+iWidth >= x1 && x<=x2 &&
           y+iHeight >= y1 && y<=y2)
            ret=true;
    }
    return ret;
}

void CMapObject::create_mo(CObjectSet *obSet, int num, DATAFILE *d, float _x, float _y, Point _p2, CCinematic *_ingameCin)
{
    init_mo();
    create_mo(obSet->return_info(num),d,_x,_y,_p2,_ingameCin);
    object_num = num;

}

void CMapObject::create_mo(ob info, DATAFILE *d, float _x, float _y, Point _p2, CCinematic *_ingameCin)
{
    init_mo();
    obInfo=info;
  
    data=d;
  
    if(strcmp(info.script_name,"none")!=0)  //=0 means true
    {
        if(script.load_script(info.script_name))
           has_script=true;
    }
  

    if(obInfo.pic_num==-1) //it is an animation
    {
        anim.create(obInfo.anim_file);
        picture_type=USEANIM;
        //anim_on=true;
        curpic=anim.return_frame(0);
        iWidth=(int)(anim.ret_first_w()*.80);
        iHeight=anim.ret_first_h();
    }
    else
    {
        //curpic=(BITMAP*)d[object01+obInfo.pic_num].dat;
        setPic((BITMAP*)d[object01+obInfo.pic_num].dat);
        curpic = pic;
        picture_type=USEBITMAP;
        iWidth = curpic->w;
        iHeight = curpic->h;
    }

    p2=_p2;
    x=_x;
    y=_y;
    dir=RIGHT;
    dx=0;

    p1.x=x;
    p1.y=y;
    finalize_movement();
    angle=atan2(p2.y-p1.y , p2.x-p1.x);
    set_angle(angle,obInfo.pickup_value);

    exist=true;

    if(info.enim_type==2 || info.enim_type==5)   //a falling rock or swooping enemy
        still=true;
        
    ingameCin = _ingameCin;
}

void CMapObject::create_mo(CMapObject *ob)
{
    init_mo();
    exist=true;
    x=ob->x;
    y=ob->y;
    dx=ob->dx;
    dy=ob->dy;
    speed=ob->speed;
    p1=ob->p1;
    p2=ob->p2;  //points for the movement of the platform

    data = ob->data;

    object_num=ob->object_num;  //reffers to the number of the object that this is based on

    picture_type=ob->picture_type;   //animation or static bitmap

    setPic(ob->pic);
    curpic = pic;
    
    //curpic=ob->pic;
    iWidth=ob->iWidth;
    iHeight=ob->iHeight;
    anim=ob->anim;
    
    if(picture_type==USEANIM)
        curpic = anim.return_current_frame();
    

    obInfo=ob->obInfo;

    set_up_points();
    finalize_movement();

    dir=RIGHT;
    dx=0;
    still=ob->still;
    has_script=ob->has_script;
    script=ob->script;
    
    ingameCin = ob->ingameCin;
}

void CMapObject::destroy(void)
{
    if(exist==true)
    {
        exist=false;
        anim.destroy();
    }
}

   /* int type, pic_num;
    char *anim_file;
    int tile_type, pickup_type, enim_type;
    int pickup_value;
    bool exist; */
void CMapObject::init_mo(void)
{
    exist=false;
    x=0;
    y=0; iWidth=0; iHeight=0;
    obInfo.type=0;
    obInfo.pic_num=0;
    strcpy(obInfo.anim_file,"none");
    obInfo.tile_type=0;
    obInfo.pickup_type=0;
    obInfo.pickup_value=0;
    obInfo.enim_type=-1;
    obInfo.grav=0;
    obInfo.moving=false;
    obInfo.exist=false;
    obInfo.consumable=false;
    picture_type=USEBITMAP;
    invinc_counter=0;

    consumed=false;

    swinging=false;
    pivot_point.x=100;
    pivot_point.y=0;
    angle2=M_PI;
    angle_vel=5;
    angle_acc=0;
    length=0;
    swing_pos_x=swing_pos_y=0;

  //  anim_on=true;
    offscreen=true;
    playing_ambient=false;
    anim.init();

    dir=RIGHT;
    dx=0;
    dy=0;
    
    ambient_voice=-1;

    script.init();
    has_script=false;
    still=false;
    
    touching_ground=false;
    not_moving=false;
    
    ingameCin=NULL;
}
