#define ANIMATION

#include "main.h"
#include "setup.h"
#include "ex.h"
#include "pixmap.h"
#include "timer.h"
#include "animation.h"

static Anime_struct top,last;
static Stack tmpid_stk;
static AmemStack animemptr;
Anime_struct animem[MAXTMP];

/* アニメーションの鎖を初期化 */
void init_animation()
{
  int i;

  top.next=&last;
  top.prev=0;
  last.prev=&top;
  last.next=0;

  init_stack(&tmpid_stk);
  init_stack(&animemptr);

  for(i=0;i<MAXTMP;i++) push(&animemptr,&animem[i]);
}

/* アニメーションの対象からはずす */
#define delete_anime(PTR)\
{\
  ((PTR)->prev)->next=(PTR)->next;\
  if((PTR)->next) ((PTR)->next)->prev=(PTR)->prev;\
  push(&animemptr,PTR);\
}

/* アニメーション中のキャラの背景を戻す */
void return_back_anime()
{
  int tmpid;

  while( (tmpid=pop(&tmpid_stk))!=-1 ) return_back(tmpid);
}

/* 鎖の破片を作る */
static Anime_struct *create_data(signed int n,int x,int y)
{
  static Anime_struct *iptr,*ptr;
  int i;

  iptr=pop(&animemptr);

  if(n>0)
  {
    n--;
    ptr=&top;
    for(i=0;i<n && ptr->next!=&last;i++) ptr=ptr->next;
  }
  else
  {
    n=-n;
    ptr=&last;
    for(i=0;i<n && ptr->prev!=0;i++) ptr=ptr->prev;
  }

  iptr->prev=ptr;
  iptr->next=ptr->next;
  (ptr->next)->prev=iptr;
  ptr->next=iptr;

  iptr->c=0;
  iptr->x=x;
  iptr->y=y;
  return iptr;
}

/* アニメ中のキャラを配置 */
#define put_sp_anime(X,Y,CID,TY)\
  (push(&tmpid_stk,put_sp(mwin,X,Y,CID,TY)))

/***************************************************************
   Cosmo
****************************************************************/

/* あぁ cosmo が飛んでいく */
static void flying_cosmo(Anime_struct *ptr)
{
  int x,y;
  double px;

  ptr->c+=rough;
  px=-0.16*ptr->n*ptr->c;
  x=ptr->x+px*(SIZE/2);
  px+=1.92*ptr->n;
  y=ptr->y+(px*px-1.92*1.92)*(SIZE/2);
  
  if(x+SIZE<0 || x>w2attr.width || y>w2attr.height)
  {
    delete_anime(ptr);
  }
  else
  {
    put_sp_anime(COSMO1,x,y,0);
  }
}

static int prs[] = { COSMO2,COSMO3,COSMO4,PA,PA };

/* cosmo を潰す */
static void press_cosmo(Anime_struct *ptr)
{
  int cid;

  if(ptr->c>=20)
  {
    delete_anime(ptr);
    return;
  }

  if(ptr->c>=16) cid=PA;
            else cid=prs[ptr->c/4];
  put_sp_anime(cid,ptr->x,ptr->y-ptr->c,0);
  ptr->c+=rough;
}

/* 飛ばす cosmo を登録する */
void entry_cosmo(int x,int y,int tmpid,int d)
{
  Anime_struct *ptr;

  if( (ptr=create_data(-1,x,y)) == NULL ) return;
  ptr->n=(d==0 ? 1 : -1);
  ptr->func=flying_cosmo;
  return_back(tmpid);
}

/* 潰す cosmo を登録する */
void entry_cosmo_p(int x,int y,int tmpid)
{
  Anime_struct *ptr;

  if( (ptr=create_data(-1,x,y)) == NULL ) return;
  ptr->func=press_cosmo;
  return_back(tmpid);
}

/***************************************************************
   Ball
****************************************************************/

static Anime_struct *ball_ptr=NULL;

/* ボールを動かす */
static void move_ball(Anime_struct *ptr)
{
  switch(ptr->n)
  {
    case LEFT:  ptr->x-=SIZE/4*rough;
		break;
    case RIGHT: ptr->x+=SIZE/4*rough;
		break;
    case DOWN:  ptr->y+=SIZE/4*rough;
		break;
  }

  put_sp_anime(BALL,ptr->x,ptr->y,0);
}

/* ボールを登録 */
void entry_ball(int x,int y,int tmpid)
{
  if( (ball_ptr=create_data(1,x,y)) == NULL ) return;
  ball_ptr->func=move_ball;
  return_back(tmpid);
}

/* ボールの向きを変える */
void chdir_ball(int d)
{
  ball_ptr->n=d;
}

/* ボールをアニメーションから削除 */
void delete_ball()
{
  if(ball_ptr)
  {
    delete_anime(ball_ptr);
    ball_ptr=NULL;
  }
}


/***************************************************************
   Pa!
****************************************************************/

/*           ＼｜／       */
/* 0.5 秒後に─パ─を消す */
/*           ／｜＼       */
static void pa(Anime_struct *ptr)
{
  ptr->c++;

  if(ptr->c>ALRM_PAR_SEC/2)
  {
    delete_anime(ptr);
  }
  else
  {
    put_sp_anime(PA,ptr->x,ptr->y,0);
  }
}

/* アニメーションに登録 */
void entry_pa(int x,int y)
{
  Anime_struct *ptr;

  if( (ptr=create_data(1,x,y)) == NULL ) return;
  ptr->func=pa;
}


/***************************************************************
   カーテン
****************************************************************/

static int cur[]={
  CURTAIN1,CURTAIN2,CURTAIN3,CURTAIN4,
  CURTAIN5,CURTAIN6,CURTAIN7,CURTAIN8
};

/* カーテン */
void curtain(Anime_struct *ptr)
{
  if(ptr->c==8*ptr->n)
  {
    delete_anime(ptr);
    return;
  }

  put_sp_anime(cur[ptr->c/ptr->n],ptr->x,ptr->y,0);
  ptr->c+=rough;
}

/* 登録 */
void entry_curtain(int x,int y,int n)
{
  Anime_struct *ptr;

  if( (ptr=create_data(2,x,y)) == NULL ) return;
  ptr->func=curtain;
  ptr->n=n;
}


/***************************************************************
   一コマ下がる、それだけ
****************************************************************/
static void fall(Anime_struct *ptr)
{
  ptr->c++;

  if(ptr->c >= 3-rough)
  {
    *(ptr->p)=put_sp(mwin,ptr->n,ptr->x,ptr->y+SIZE,0);
    delete_anime(ptr);
    return;
  }

  *(ptr->p)=
    put_sp_anime(ptr->n,ptr->x,ptr->y+ptr->c*SIZE/(3-rough),0);
}

/* 登録 */
void entry_fall(int x,int y,int cid,int tmpid,int *tmpp)
{
  Anime_struct *ptr;

  if( (ptr=create_data(1,x,y)) == NULL ) return;
  ptr->n=cid;
  ptr->p=tmpp;
  ptr->func=fall;
  return_back(tmpid);
}


/***************************************************************
   SCORE 表示
****************************************************************/
static int num[3][11] = {
 { B0,B1,B2,B3,B4,B5,B6,B7,B8,B9,Sx },
 { S0,S1,S2,S3,S4,S5,S6,S7,S8,S9,Sx }
};

static void score(Anime_struct *ptr)
{
  int y;

  ptr->c+=rough;
  if(ptr->c==SIZE)
  {
    delete_anime(ptr);
    user.score+=ptr->n;
    put_scr(user.score);
    XSetForeground(disp,gc,0);
    XFillRectangle(disp,chara,gc,0,sp[SCORE].y,sp[SCORE].width,32);
    XSetForeground(disp,gc,0xffffffff);
    XFillRectangle(disp,mask ,gc,0,sp[SCORE].y,sp[SCORE].width,32);
    return;
  }

  if(ptr->c>SIZE/2) y=ptr->y-SIZE;
               else y=ptr->y-ptr->c*2;

  put_sp_anime(SCORE,ptr->x,y,SIZE);
}

static char *itoa(int n)
{
  static char num[10];
  signed int i;

  num[9]='\0';
  for(i=8;i>=0 && n>0;i--)
  {
    num[i]=n%10+'0';
    n/=10;
  }

  return &num[i+1];
}

/* 登録 */
void entry_score(signed int x,signed int y,int s1,int s2)
{
  int dy=0,wd;
  int i;
  int c,l,s2f=0;
  char buf1[16];
  Anime_struct *ptr;

  strcpy(buf1,itoa(s1));
  if(s2>1)
  {
    dy=16;
    s2f=1;
    strcat(buf1,"x");
    strcat(buf1,itoa(s2));
  }

  l=strlen(buf1);
  wd=(l*18+6);
  x=x-wd/2;
  if(x<0) x=0;
  if(x+wd>w2attr.width) x=w2attr.width-wd;
  if(y-SIZE<0) y=SIZE;

  if( (ptr=create_data(-1,x,y)) == NULL ) return;
  ptr->n=s1*s2;
  ptr->func=score;

  sp[SCORE].width=wd;

  for(i=l-1;i>=0;i--)
  {
    if(buf1[i]=='x') { c=10; s2f--; }
                else c=buf1[i]-'0';

    place_chara(chara,num[s2f][c],i*18,sp[SCORE].y+dy);
    XCopyArea(disp,mask,mask,and_gc,
	      sp[num[s2f][c]].x,sp[num[s2f][c]].y,
	      sp[num[s2f][c]].width,sp[num[s2f][c]].height,
	      i*18,sp[SCORE].y+dy);
    if(s2f==0) dy=0;
  }
}


/***************************************************************
   登録した Animation を実際に行なう
****************************************************************/
int animation()
{
  Anime_struct *ptr;

  if(top.next==&last) return 0;

  ptr=top.next;
  while(ptr->next)
  {
    ptr->func(ptr);
    ptr=ptr->next;
  }

  x_flush();

  return_back_anime();

  return 1;
}
