/********************************
  netpuyo(client)
  game.c --- game operation
  (C) Oct 6, 1997 ROYALPANDA
*******************************/

#include<stdio.h>

#include"netpuyo.h"
#include"protocol.h"

#define MD_WAIT  0
#define MD_FALL  1
#define MD_KILL  2
#define MD_JAMA  3

/* プレーヤーの状態 */
static int Mode[2];

/* 組ぷよを操作中か */
static int Moving;

/* 向きに対応する相対座標 */

static int Dir_x[4] = { 0,1,0,-1 };
static int Dir_y[4] = { -1,0,1,0 };


/* 対戦の初期化 */

void init_game( void )
{
  int p,x,y;

  Moving = 0;
  for( p = 0 ; p < 2 ; p++ ){
    Mode[p] = MD_WAIT;

    for( y = 0 ; y < 13 ; y++ ){
      P[p].map_c[0][y] = WALL;
      P[p].map_c[7][y] = WALL;
      for( x = 1 ; x < 7 ; x++ )
	P[p].map_c[x][y] = NOTHING;
    }
    for( x = 0 ; x < 8 ; x++ )
      P[p].map_c[x][13] = WALL;

    flush_scr(p);

    P[p].next[0] = -1;
    P[p].stock = 0;
    P[p].moving = 0;

    stock(p);
  }
}


/* アニメーション完了メッセージを送る */

static void okay( int p )
{
  Mode[p] = MD_WAIT;
  send_init( MSG_OKAY );
  send_id( p );
  send_msg();
  if( Mode[1-p] == MD_WAIT )
    reset_timer( 0 );
}


/* 組ぷよの位置を送る */
static void send_move( void )
{
  send_init(MSG_PUTP);
  send_snum( P[0].x[0] );
  send_snum( P[0].y[0] );
  send_snum( P[0].x[1] );
  send_snum( P[0].y[1] );
  send_msg();
}


/* 組ぷよを動かす */

void move( int d )
{
  if( !Moving )
    return;

  if( P[0].map_c[P[0].x[0]+d][P[0].y[0]] != NOTHING )
    return;

  if( P[0].map_c[P[0].x[1]+d][P[0].y[1]] != NOTHING )
    return;

  del_puyo( 0 );

  P[0].x[0] += d;
  P[0].x[1] += d;

  send_move();
  move_puyo( 0 );
}


/* 組ぷよの回転 */

void rotate( int d )
{
  int dir,x,y;

  if( !Moving )
    return;

  dir = ( P[0].dir + d + 4 ) % 4;

  x = P[0].x[0] + Dir_x[dir];
  y = P[0].y[0] + Dir_y[dir];

  if( P[0].map_c[x][y] == NOTHING  ){
    del_puyo( 0 );
    P[0].dir = dir;
    P[0].x[1] = x;
    P[0].y[1] = y;
    send_move();
    move_puyo( 0 );
  }else if( dir == 1 || dir == 3 ){
    x = P[0].x[0] - Dir_x[dir];
    y = P[0].y[0] - Dir_y[dir];
    if( P[0].map_c[x][y] == NOTHING ){
      del_puyo( 0 );
      P[0].dir = dir;
      P[0].x[1] = P[0].x[0];
      P[0].y[1] = P[0].y[0];
      P[0].x[0] = x;
      P[0].y[0] = y;
      send_move();
      move_puyo( 0 );
    }
  }
}


/* 組みぷよの上下を入れ換える */

int turn( void )
{
  int y;

  if( !Moving )
    return 0;

  if( P[0].dir & 1 )
    return 0;

  if( P[0].map_c[P[0].x[0]+1][P[0].y[0]] == NOTHING ||
     P[0].map_c[P[0].x[0]-1][P[0].y[0]] == NOTHING )
    return 0;

  del_puyo( 0 );
  y = P[0].y[0];
  P[0].y[0] = P[0].y[1];
  P[0].y[1] = y;
  P[0].dir = ( P[0].dir+2) % 4;
  send_move();
  move_puyo( 0 );
  return 1;
}


/* 組ぷよの落下、まだ動ければ 1 を返す */
int fall( void )
{
  del_puyo( 0 );

  if( P[0].map_c[P[0].x[0]][P[0].y[0]+1] != NOTHING ||
     P[0].map_c[P[0].x[1]][P[0].y[1]+1] != NOTHING ){

    P[0].map_c[P[0].x[0]][P[0].y[0]] = P[0].puyo[0];
    P[0].map_c[P[0].x[1]][P[0].y[1]] = P[0].puyo[1];

    flush_scr( 0 );

    send_init( MSG_STOP );
    send_msg();

    Moving = 0;
    Mode[0] = MD_FALL;
    set_timer(0);
    return 0;
  }else{
    P[0].y[0]++;
    P[0].y[1]++;
    send_move();
    move_puyo( 0 );
    return 1;
  }
}

/* サーバーからのメッセージの処理 */

void recieve( void )
{
  int msg;
  int x,y,c;
  int p,i,m,mode;
  char kill_msg[32];

  while( (msg = recv_msg()) ){
    switch( msg ){
    case MSG_MOVE:
      P[0].puyo[0] = recv_snum();
      P[0].puyo[1] = recv_snum();
      P[0].next[0] = recv_snum();
      P[0].next[1] = recv_snum();
      P[0].next[2] = recv_snum();
      P[0].next[3] = recv_snum();
      P[0].x[0] = 3;
      P[0].x[1] = 3;
      P[0].y[0] = 1;
      P[0].y[1] = 0;
      P[0].dir = 0;
      move_puyo( 0 );
      draw_next( 0 );
      message(0,"");
      start_move();
      Moving = 1;
      break;

    case MSG_NEXT:
      P[1].next[0] = recv_snum();
      P[1].next[1] = recv_snum();
      P[1].next[2] = recv_snum();
      P[1].next[3] = recv_snum();
      draw_next( 1 );
      message(1,"");
      break;

    case MSG_PUYO:
      if( P[1].moving )
	del_puyo( 1 );
      else
	P[1].moving = 1;
      P[1].puyo[0] = recv_snum();
      P[1].x[0] = recv_snum();
      P[1].y[0] = recv_snum();
      P[1].puyo[1] = recv_snum();
      P[1].x[1] = recv_snum();
      P[1].y[1] = recv_snum();
      move_puyo( 1 );
      break;
      
    case MSG_STND:
      c = recv_snum();
      x = recv_snum();
      y = recv_snum();
      P[1].map_c[x][y] = c;
      c = recv_snum();
      x = recv_snum();
      y = recv_snum();
      P[1].map_c[x][y] = c;
	
      flush_scr( 1 );
      Mode[1] = MD_FALL;
      P[1].moving = 0;
      set_timer(0);
      break;
      
    case MSG_KILL:
      p = recv_id();
      m = recv_snum();
      for( i = 1 ; i < 13 ; i++ )
	P[p].kill[i] = recv_snum();
      P[p].blink = 15;

      mode = recv_snum();
      
      if( mode & 4 )
	sprintf(kill_msg,"Delete all!!!");
      else
	switch( m % 10 ){
	case 1:
	  sprintf(kill_msg,"Series %dst!!",m );
	  break;
	case 2:
	  sprintf(kill_msg,"Series %dnd!!",m );
	  break;
	case 3:
	  sprintf(kill_msg,"Series %drd!!",m );
	  break;
	default:
	  sprintf(kill_msg,"Series %dth!!",m );
	  break;
	}
      
      message( p,kill_msg );

      P[My_id].stock_next  = recv_lnum();
      P[1-My_id].stock_next  = recv_lnum();

      Mode[p] = MD_KILL;
      set_timer(0);
      break;

    case MSG_JAMA:
      p = recv_id();
      P[p].jama_line = recv_snum();
      P[p].jama_top = recv_snum();
      P[p].stock = recv_lnum();
      stock(p);
      Mode[p] = MD_JAMA;
      set_timer(0);
      break;
      
    case MSG_WINR:
      winner( recv_snum() );
      return;
      break;

    case MSG_TALK:
      chat();
      break;

    case MSG_QUIT:
      quit();
      return;
      break;
    }
  }
}


/* 対戦中のアニメーション処理 */

void animation( void )
{
  int p;

  for( p = 0 ; p < 2 ; p++ )
    switch( Mode[p] ){

    case MD_FALL:
      if( !fall_puyo( p ) )
	okay( p );
      break;

    case MD_KILL:
      if( !blink_puyo( p ) ){
	if( P[0].stock_next != P[0].stock ){
	  P[0].stock = P[0].stock_next;
	  stock( 0 );
	}
	if( P[1].stock_next != P[1].stock ){
	  P[1].stock = P[1].stock_next;
	  stock( 1 );
	}
	Mode[p] = MD_FALL;
      }
      break;

    case MD_JAMA:
      if( !jama_puyo( p ) )
	Mode[p] = MD_FALL;
      break;
    }
}
