#include <stdlib.h>
#include <stdio.h>
#include <sys/bios.h>

#define ABS(a) (0<(a)?(a):-(a))

typedef union {
  struct {
    unsigned char f ;
    unsigned char i ;
  } p ;
  unsigned int w ;
  int s ;
} fixed_t ;

int graph_init( int ) ;
void clear();
int pset( int , int , int ) ;
int line( int , int , int , int , int ) ;
int box( int , int , int , int , int ) ;
int circle( int , int , int , int ) ;
int point( int,int );


#define AMX 90
#define AC 100
#define WALL 1
#define TARGET 2
#define DOT 7

int keysens(void);

int x,y,z;
int X0,Y0;
int ax,ay,az;
int MMM;

typedef struct tgDDD 
{
 char command;
 int D1;
 int D2;
 int D3;
 int D4;
} Dst;

/*面データ*/
Dst DATA[]=
{
{'L',35,0,69,87},
{'L',129,39,164,142},
{'E',0,0,0,0},

{'R',43,8,63,89},
{'R',103,134,121,37},
{'R',160,16,209,98},
{'E',0,0,0,0},

{'C',55,26,23,0},
{'C',130,91,47,0},
{'C',196,20,25,0},
{'E',0,0,0,0},

{'R',41,21,50,121},
{'R',75,142,83,50},
{'R',123,1,146,120},
{'C',211,130,34,0},
{'C',211,14,38,0},
{'E',0,0,0,0},

{'R',0,0,165,41},
{'R',165,98,0,143},
{'R',44,68,184,72},
{'R',197,23,205,120},
{'E',0,0,0,0},

{'C',95,62,62,0},
{'C',187,111,21,0},
{'C',203,129,20,0},
{'C',203,58,24,0},
{'P',14,15,14,15},
{'E',0,0,0,0},

{'L',64,0,140,58},
{'L',140,74,70,141},
{'L',140,124,167,67},
{'L',167,63,133,12},
{'R',196,1,208,57},
{'R',208,76,196,143},
{'P',15,74,15,74},
{'E',0,0,0,0},

{'R',105,58,74,25},
{'R',23,21,42,127},
{'R',35,119,149,141},
{'R',79,53,64,100},
{'R',96,121,117,75},
{'R',128,62,140,0},
{'R',93,0,103,30},
{'C',148,115,12,0},
{'C',161,96,15,0},
{'C',164,77,6,0},
{'C',169,68,5,0},
{'C',169,59,7,0},
{'C',175,45,10,0},
{'C',187,27,13,0},
{'C',200,19,6,0},
{'R',218,0,224,112},
{'C',196,125,10,0},
{'C',200,107,10,0},
{'P',11,66,11,66},
{'E',0,0,0,0},

{'L',125,68,218,0},
{'L',218,142,123,84},
{'L',156,17,74,78},
{'L',75,78,139,125},
{'L',75,142,43,89},
{'L',43,61,78,0},
{'C',88,33,8,0},
{'C',83,117,6,0},
{'E',0,0,0,0},

{'C',136,67,31,0},
{'C',157,92,38,0},
{'C',157,29,18,0},
{'C',91,60,19,0},
{'C',116,81,115,0},
{'P',20,75,20,75},
{'E',0,0,0,0},

{'R',180,55,0,59},
{'R',34,102,195,98},
{'R',201,101,193,23},
{'R',193,23,31,26},
{'R',0,10,210,14},
{'R',217,0,223,45},
{'R',217,43,197,38},
{'R',217,83,220,143},
{'R',203,143,18,119},
{'C',34,77,5,0},
{'C',68,78,6,0},
{'C',122,78,7,0},
{'C',155,78,6,0},
{'P',3,3,0,0},
{'E',0,0,0,0},

{'C',97,67,24,0},
{'C',160,119,51,0},
{'C',160,1,59,0},
{'C',131,94,9,0},
{'C',118,11,8,0},
{'L',61,74,19,83},
{'P',11,17,11,17},
{'E',0,0,0,0},

{'R',102,8,106,132},
{'R',187,142,190,19},
{'R',148,0,151,127},
{'R',54,142,51,13},
{'P',12,131,12,131},
{'E',0,0,0,0},

{'C',61,28,3,0},
{'C',76,42,7,0},
{'C',68,68,5,0},
{'C',67,87,3,0},
{'C',99,90,4,0},
{'C',112,106,2,0},
{'C',112,114,4,0},
{'C',104,128,8,0},
{'C',155,132,10,0},
{'C',162,98,5,0},
{'C',169,89,3,0},
{'C',170,80,3,0},
{'C',170,73,4,0},
{'C',170,58,5,0},
{'C',179,39,13,0},
{'C',181,12,10,0},
{'C',203,19,6,0},
{'C',142,11,7,0},
{'E',0,0,0,0},


{'C',202,127,11,0},
{'C',202,96,14,0},
{'C',202,65,10,0},
{'C',202,44,6,0},
{'C',202,21,12,0},
{'C',176,1,14,0},
{'C',176,29,10,0},
{'C',176,52,7,0},
{'C',176,75,9,0},
{'C',176,96,6,0},
{'C',176,115,10,0},
{'C',176,138,11,0},
{'R',113,136,95,114},
{'R',82,108,65,146},
{'R',65,92,82,39},
{'R',88,22,104,47},
{'R',93,81,105,110},
{'R',113,91,119,33},
{'R',94,54,110,64},
{'R',111,24,116,0},
{'R',101,0,64,13},
{'R',63,21,77,30},
{'R',48,6,52,133},
{'P',10,68,10,68},


{'Z',0,0,0,0}

};

/*爆発*/
int bomb()
{
	int i;
	for(i=0;i<512;i++)
		circle(223-10+rand()/1000,70+rand()/100,5*rand()/500,5);

}

/*爆発ゲームオーバー*/
int bomb2()
{
	int i;
	for(i=0;i<200;i++)
		circle(X0+x/AC,Y0+y/AC,i,rand()*5/1000);

}

void FIELD(int MEN)
{
int i;
int cnt;
clear();
x=0;
y=0;
ax=0;
ay=0;

graph_init( 0 );
box(0,0,223,143,WALL);

X0=5; 	Y0=72;

for(cnt=0,i=0;i<1000;i++)
{
if(cnt==MEN-1) break;
if(DATA[i].command=='E') cnt++;
if(DATA[i].command=='Z') {i=-1;cnt++;}
}

for(;i<1000;i++)
{
if(DATA[i].command=='E')  break;
if(DATA[i].command=='L')  line( DATA[i].D1 , DATA[i].D2 , DATA[i].D3 , DATA[i].D4 , WALL ) ;
if(DATA[i].command=='R')  box( DATA[i].D1 , DATA[i].D2 , DATA[i].D3 , DATA[i].D4 , WALL ) ;
if(DATA[i].command=='C')  circle( DATA[i].D1 , DATA[i].D2 , DATA[i].D3 , WALL ) ;
if(DATA[i].command=='P') { X0=DATA[i].D1; 	Y0=DATA[i].D2;}

}
line( 223 , 0 , 223 , 143 , TARGET ) ;
    ax=0;
	ay=0;
}

int LINE=0;
void PRINT(char *str)
{
 text_put_string(0,LINE++,str);
}
void OP()
{
	text_screen_init();
	LINE=0;
	PRINT(" " );
	PRINT("  :::  ::::  ::::  :   :    " );
	PRINT("  :  : :     :     :: ::    " );
	PRINT("  :::  ::::  ::::  : : :    " );
	PRINT("  :  : :     :     :   :    " );
	PRINT("  :::: ::::: ::::  :   :    " );
/*	PRINT("1234567890123456789012345678" );*/
	PRINT(" " );
	PRINT("宇宙世紀３０００年。");
	PRINT("太陽系は強力な重力場「エネルギーリボン」に飲み込まれようとしていた。　地球防衛軍は重力場位相反転兵器「ＢＥＥＭ」の開発に成功した。" );
	PRINT("" );
	PRINT("" );
	PRINT("ただ、この兵器は人の手で操縦する必要があるという欠点があるのだ。" );
	PRINT("迎撃部隊に配属されたあなたは。地球を救うことができるのか！？" );
	PRINT("" );
	PRINT("" );
	PRINT("Ｘキー上下左右でＢＥＥＭを操作して障害物を避け画面右端のエネルギーリボンを迎撃せよ。" );
	PRINT("" );
	PRINT("2001 (C)きはら　たかえい" );
	key_wait();

}

int main()
{
	int i , c ,j ;
	int key;
    char text[128];
	x=100;
	y=100;
    ax=0;
	ay=0;
    MMM=1;


	OP();
	if( !graph_init( 0 ) ) return ;

while(1)
{
	FIELD(MMM);

while(1)
{
	c=point(X0+x/AC,Y0+y/AC);
	if(c==WALL)   break;
	if(c==TARGET) break;
	if((key=key_press_check()) == KEY_START) break;
	if(key == KEY_RIGHT2) break;
/* DISP */
	pset(X0+x/AC,Y0+y/AC,DOT);

    keysens();

    x+=(ax);
    y+=(ay);
    for(j=0;j<50;j++)
      for(i=0;i<100;i++);
}

	if(key== KEY_START) break;
	if(c==WALL)
	{
		bomb2();
		graph_init(1);
		text_screen_init();
		sprintf(text,"STAGE No. %d ",MMM);
    	text_put_string( 8, 10, text );
    	text_put_string( 8, 8, "Game is Over" );
		key_wait();
		break;
	}
	if(c==TARGET)
	{
		bomb();
		graph_init(1);
		text_screen_init();
		sprintf(text,"STAGE No. %d Clear.",MMM);
    	text_put_string( 5, 5, text );
    	text_put_string( 5, 8, "GOOD!! TRY NEXT STAGE!!" );
    	text_put_string( 5, 10, "       Hit A KEY!      " );
        while(key_press_check() != KEY_A);
		MMM++;
		text_screen_init();
		graph_init(0);
	}
	if(key==KEY_RIGHT2)
	{
		bomb();
		graph_init(1);
		text_screen_init();
		sprintf(text,"STAGE No. %d Clear.",MMM);
    	text_put_string( 5, 5, text );
    	text_put_string( 5, 8, "GOOD!! TRY NEXT STAGE!!" );
    	text_put_string( 5, 10, "       Hit A KEY!      " );
        while(key_press_check() != KEY_A);
		MMM++;
		text_screen_init();
		graph_init(0);
	}


}
 return;
}

int keysens(void)
{
int key;

	key = key_press_check();	
	if (key&KEY_LEFT1 )
	{
		if(ax>-AMX) ax--;
	}

	if (key&KEY_RIGHT1)
	{
		if(ax<AMX) ax++;
	}
	if (key&KEY_UP1)
	{
		if(ay>-AMX) ay--;
	}
	if (key&KEY_DOWN1 )
	{
		if(ay<AMX) ay++;
	}
	if (key&KEY_A     ) az++;
	if (key&KEY_B     ) az--;

}

static int dispno ;
static unsigned int fontdata[28*18][8] ;


int graph_init(int d )
{
  unsigned int ch[28*18] ;
  unsigned int d_ctrl ; 
  int i ;

  d_ctrl = display_status() ;
  switch ( d ) {
   case SCREEN1:
    d_ctrl |= DCM_SCR1 ;
    d_ctrl &= ~DCM_SCR2 ;
    break ;
   case SCREEN2:
    d_ctrl |= DCM_SCR2 ;
    d_ctrl &= ~DCM_SCR1 ;
    break ;
   default:
    return 0 ;
  }
  display_control( d_ctrl ) ;


  clear() ;

  for ( i = 0 ; i < 28*18 ; i++ ) {
    ch[i] = i ;
  }
  screen_set_char( dispno , 0 , 0 , 28 , 18 , ch ) ;

  return 1 ;
}


void clear()
{

  memset( fontdata , 0 , 28*18*16 ) ;
  font_set_colordata( 0 , 28*18 , fontdata ) ;

  return ;
}


int pset(int x ,int y ,int c )
{
  unsigned int *font_p ;
  int idx ;

  if ( x<0 || 224<=x || y<0 || 144<=y ) {
    return 0 ;
  }

  idx = (y/8)*28 + x/8 ;
  font_p = &(fontdata[idx][y&7]) ;

  switch ( c & 3 ) {
   case 0:
    *font_p &= ~(32896>>(x&7)) ;
    break ;
   case 1:
    *font_p |= 128>>(x&7) ;
    *font_p &= ~(32768>>(x&7)) ;
    break ;
   case 2:
    *font_p &= ~(128>>(x&7)) ;
    *font_p |= 32768>>(x&7) ;
    break ;
   case 3:
    *font_p |= 32896>>(x&7) ;
    break ;
  }

  font_set_colordata( idx , 1 , fontdata[idx] ) ;

  return 1 ;
}

int line(int x0 ,int y0 ,int x1 ,int y1 ,int c )
{
  fixed_t x , y , vx , vy ;

  if (    x0<0 || 224<=x0 || y0<0 || 144<=y0
       || x1<0 || 224<=x1 || y1<0 || 144<=y1 ) {
    return 0 ;
  }

  if ( ABS(x1-x0) > ABS(y1-y0) ) {
    vx.s = (x0<x1?256:-256) ;
    vy.s = (y1-y0)*128 / ABS(x1-x0) * 2 ;
  } else {
    vx.s = (x1-x0)*128 / ABS(y1-y0) * 2 ;
    vy.s = (y0<y1?256:-256) ;
  }

  x.w = x0 * 256 + 128 ;
  y.w = y0 * 256 + 128 ;

  pset( x.p.i , y.p.i , c ) ;
  while ( x.p.i != x1 || y.p.i != y1 ) {
    x.w += vx.w ;
    y.w += vy.w ;
    pset( x.p.i , y.p.i , c );
  }
  return 1 ;
}

int box( int x0 , int y0 ,int  x1 ,int  y1 ,int  c )
{
line( x0 , y0 , x1 ,y0, c );
line( x1 , y0 , x1 ,y1, c );
line( x1 , y1 , x0 ,y1, c );
line( x0 , y1 , x0 ,y0, c );

}


int point(int x ,int y )
{
  int idx , c ;

  if ( x<0 || 224<=x || y<0 || 144<=y ) {
    return -1 ;
  }

  idx = (y/8)*28 + x/8 ;
  c = fontdata[idx][y&7] >> (7-(x&7)) ;
  switch ( c & 257 ) {
   case 0:
    return 0 ;
   case 1:
    return 1 ;
   case 256:
    return 2 ;
   case 257:
    return 3 ;
  }
  return -1 ;
}

int circle(int x ,int y ,int r ,int c )
{
  int a , b , u , v , uu , vv , r2 ;

  r2 = r * r ;

  a  = r     ;
  b  = 0     ;
  u  = r2-r  ;
  v  = 0     ;
  uu = r*2-2 ;
  vv = 1     ;

  while ( a >= b ) {
    pset( x + a , y + b , c ) ;
    pset( x + a , y - b , c ) ;
    pset( x - a , y + b , c ) ;
    pset( x - a , y - b , c ) ;
    pset( x + b , y + a , c ) ;
    pset( x + b , y - a , c ) ;
    pset( x - b , y + a , c ) ;
    pset( x - b , y - a , c ) ;
    b++ ;
    v += vv , vv += 2 ;
    if ( r2 - v < u ) {
      --a ;
      u -= uu , uu -= 2 ;
    }
  }
  return 1 ;
}

