/*-
 * Copyright (c) 2000
 * Tatsuya Kudoh(CDR/TK),ROYALPANDA.    All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */
#include<stdlib.h>
#include<stdio.h>
#include<sys/bios.h>

#include"soari.h"

#include"fontdata.h"


static const unsigned Hero_l1[16] = {
	0,1,2,3,
	28,29,30,31,
	56,57,58,59,
	84,85,86,87,
};

static const unsigned Hero_l2[16] = {
	4,5,6,7,
	32,33,34,35,
	60,61,62,63,
	88,89,90,91,
};

static const unsigned Hero_r2[16] = {
	8,9,10,11,
	36,37,38,39,
	64,65,66,67,
	92,93,94,95,
};

static const unsigned Hero_r1[16] = {
	12,13,14,15,
	40,41,42,43,
	68,69,70,71,
	96,97,98,99,

};

static const unsigned Hero_la[24] = {
	16,17,18,19,20,21,
	44,45,46,47,48,49,
	72,73,74,75,76,77,
	100,101,102,103,104,105,
};

static const unsigned Hero_ra[24] = {
	22,23,24,25,26,27,
	50,51,52,53,54,55,
	78,79,80,81,82,83,
	106,107,108,109,110,111,
};


static const sprite_t Hero_spr[6] = {
	{ (unsigned*)Hero_l1, 4, 4, 0, -32 },	/* 0: Left 1 */
	{ (unsigned*)Hero_r1, 4, 4, 0, -32 },	/* 1: Right 1 */
	{ (unsigned*)Hero_l2, 4, 4, 0, -32 },	/* 2: Left 2 */
	{ (unsigned*)Hero_r2, 4, 4, 0, -32 },	/* 3: Right 2 */
	{ (unsigned*)Hero_la, 6, 4, -16, -32 },	/* 4: Left/Attack */
	{ (unsigned*)Hero_ra, 6, 4, 0, -32 },	/* 5: Right/Attack */
};

static unsigned Ene_font[4][4][16];
static sprite_t Ene_spr[4][4];

static int Ene_life_active;


#define MAX_SPRITES	512	/* must be 16 * N */

static unsigned Spr_buf[MAX_SPRITES*2];
static unsigned *Spr_wrptr;
static int Num_spr;
static int Spr_start;


static int Scr_x;
static int Scr_y;

#define PLT_BACK	0
#define VAL_PLT_BACK	0x2100
#define PLT_DARK	1
#define VAL_PLT_DARK	0x0000
#define PLT_TITLE	2
#define VAL_PLT_TITLE	0x3070

#define PLT_LIFE	4
#define VAL_PLT_LIFE	0x7020
#define PLT_ATTACK	5
#define VAL_PLT_ATTACK	0x7000
#define PLT_FLOOR	6
#define VAL_PLT_FLOOR	0x5400
#define PLT_LETTER	7
#define VAL_PLT_LETTER	0x7700

#define PLT_CHAR	12
#define VAL_PLT_CHAR	0x7400
#define PLT_DAMAGE	13
#define VAL_PLT_DAMAGE	0x7770

#define LETTER_FONT	448

#define FONT_ATTACK_FULL	505
#define FONT_ATTACK_EMPTY	506
#define FONT_ATTACK		507
#define FONT_LIFE_FULL		508
#define FONT_LIFE_EMPTY		509
#define FONT_LIFE_HERO		510
#define FONT_LIFE_ENEMY		511

static unsigned Letter_conv_table[256];

static unsigned Map_font[2][4] = {
	{ PLT_BACK<<9|368,PLT_BACK<<9|369,PLT_BACK<<9|372,PLT_BACK<<9|373 },
	{ PLT_FLOOR<<9|370,PLT_FLOOR<<9|371,PLT_FLOOR<<9|374,PLT_FLOOR<<9|375 },
};


static void create_letter( unsigned font_no, int ch )
{
	unsigned char font[9];
	unsigned buf[8];
	int j;

        font[0] = 0;
	text_get_fontdata(ch,(void far*)(font+1));
	for( j = 0 ; j < 8 ; j++ ){
		buf[j] =  (unsigned)font[j+1] << 9
			| (unsigned)font[j+1] << 1
			| (unsigned)font[j];
	}
	font_set_colordata(font_no,1,(void far*)buf);
	Letter_conv_table[ch] = PLT_LETTER<<9 | font_no;
}


static void create_lifebar( int fn, int value )
{
	unsigned buf[8];
	int i;

	value = 0xff00 << (8-value) | 0x00ff;

	buf[0] = 0x0000;
	buf[1] = 0xff00;
	for( i = 2 ; i < 6 ; i++ )
		buf[i] = value;
	buf[6] = 0xff00;
	buf[7] = 0x0000;

	font_set_colordata(fn,1,(void far*)buf);
}

static void create_attackbar( int fn, int value )
{
	unsigned buf[8];
	int i;

	value = 0xff00 << (8-value) | 0x00ff;

	buf[0] = 0x0000;
	buf[0] = 0xff00;
	buf[1] = value;
	buf[2] = value;
	buf[3] = value;
	buf[4] = 0xff00;
	for( i = 5 ; i < 8 ; i++ )
		buf[i] = 0x0000;

	font_set_colordata(fn,1,(void far*)buf);
}


void init_disp( void )
{
	int i,j;
	int x,y;
	unsigned *p;

	display_control(0);

	for( i = 0 ; i < 4 ; i++ ){
		for( j = 0 ; j < 4 ; j++ ){
			p = Ene_font[i][j];
			for( y = 0 ; y < 4 ; y++ )
				for( x = 0 ; x < 4 ; x++ )
					*p++ = y*16+x + i*64 + j * 4 + 112;
			Ene_spr[i][j].data = Ene_font[i][j];
			Ene_spr[i][j].width = 4;
			Ene_spr[i][j].height = 4;
			Ene_spr[i][j].off_x = 0;
			Ene_spr[i][j].off_y = -31;
		}
	}

	lcd_set_color(0x7aef,0x0136);

	palette_set_color(PLT_CHAR,VAL_PLT_CHAR);
	palette_set_color(PLT_DAMAGE,VAL_PLT_DAMAGE);
	palette_set_color(PLT_DARK,VAL_PLT_DARK);
	palette_set_color(PLT_TITLE,VAL_PLT_TITLE);

	palette_set_color(PLT_FLOOR,VAL_PLT_FLOOR);
	palette_set_color(PLT_BACK,VAL_PLT_BACK);
	palette_set_color(PLT_LETTER,VAL_PLT_LETTER);
	palette_set_color(PLT_LIFE,VAL_PLT_LIFE);
	palette_set_color(PLT_ATTACK,VAL_PLT_ATTACK);


	for( i = 0 ; i < 256 ; i++ )
		Letter_conv_table[i] = PLT_LETTER<<9 | LETTER_FONT;

	create_letter(LETTER_FONT,' ');

	for( i = 0 ; i < 10 ; i++ )
		create_letter(LETTER_FONT+i+1,'0'+i);

	for( i = 0 ; i < 26 ; i++ )
		create_letter(LETTER_FONT+i+11,'A'+i);

	create_letter(LETTER_FONT+37,'(');
	create_letter(LETTER_FONT+38,')');
	create_letter(LETTER_FONT+39,'.');
	create_letter(LETTER_FONT+40,'>');

	create_lifebar(FONT_LIFE_FULL,8);
	create_lifebar(FONT_LIFE_EMPTY,0);
	create_attackbar(FONT_ATTACK_FULL,8);
	create_attackbar(FONT_ATTACK_EMPTY,0);

	screen_fill_char(1,0,0,32,32,PLT_DARK<<9|LETTER_FONT);


	/* scroll */

	screen_set_scroll(0,0,0);
	screen_set_scroll(1,4,4);

	display_control(DCM_SCR1|DCM_SCR2|DCM_SPR|3<<8);

	Spr_wrptr = Spr_buf;
	Num_spr = 0;
	Spr_start = 0;
}

void set_fontdata_game( void )
{
	font_set_colordata(0,NUM_FONT_DATA,(void far*)Font_data);
}


void draw_map( int x, int y, int ex, int ey, map_t *mp )
{
	unsigned char *p;
	int mx,my;
	int sx,sy;
	int xx;

	if( x < 0 )
		x = 0;

	 if( ex >= mp->width*16 )
		ex = mp->width*16-1;

	if( y < 0 )
		y = 0;

	if( ey >= mp->height*16 )
		ey = mp->height*16-1;

	if( x > ex || y > ey )
		return;

	my = y / 16;
	while( y <= ey ){
		mx = x / 16;
		xx = x;
		p = mp->map + my * MAP_WIDTH + mx;
		while( xx <= ex ){
			sx = (mx & 15) * 2;
			sy = (my & 15) * 2;
			screen_set_char(0,sx,sy,2,2,(void far*)Map_font[*p]);
			p++;
			mx++;
			xx += 16;
		}
		my++;
		y += 16;
	}
}



int regist_sprite( sprite_t *p, int x, int y, unsigned palette )
{
	int xx;
	int w,h;
	unsigned *fp;

	if( p->width * p->height + Num_spr >= MAX_SPRITES )
		return -1;

	x = x + p->off_x - Scr_x;
	y = y + p->off_y - Scr_y;
	fp = p->data;

	h = p->height;
	while( h-- ){
		if( y >= -8 && y < 144 ){
			xx = x;
			w = p->width;
			while( w-- ){
				if( xx > -8 && xx < 224 ){
					*Spr_wrptr++ = palette | *fp;
					*Spr_wrptr++ = (xx&255)<<8 | (y&255);
					Num_spr++;
				}
				xx += 8;
				fp++;
			}
		}else{
			fp += p->width;
		}
		y += 8;
	}
	return 0;
}

void clear_sprite( void )
{
	sprite_set_range(0,0);
	Spr_wrptr = Spr_buf;
	Num_spr = 0;
}


void init_scroll( map_t *mp, int x, int y )
{
	Scr_x = x/4 - 96;
	Scr_y = y/4 - 88;

	if( Scr_x < 0 )
		Scr_x = 0;
	else if( Scr_x > mp->width * 16 - 224 )
		Scr_x = mp->width * 16 - 224;

	if( Scr_y < 0 )
		Scr_y = 0;
	else if( Scr_y > mp->height * 16 - 144 )
		Scr_y = mp->height * 16 - 144;

	draw_map(Scr_x-15,Scr_y-15,Scr_x+239,Scr_y+159,mp);
}


void scroll( map_t *mp, int x, int y )
{
	int dx,dy;
	int mx,my;

	x = x/4 - 96;
	y = y/4 - 88;


	if( x < Scr_x-8 ){
		dx = - (((Scr_x-8) - x) / 4);
		if( dx < -16 )
			dx = -16;
	}else if( x > Scr_x+8 ){
		dx = (x - (Scr_x+8)) / 4;
		if( dx > 16 )
			dx = 16;
	}else{
		dx = 0;
	}

	if( y < Scr_y-4 ){
		dy = - (((Scr_y-4) - y) / 4);
		if( dy < -16 )
			dy = -16;
	}else if( y > Scr_y+4 ){
		dy = (y - (Scr_y+4)) / 4;
		if( dy > 16 )
			dy = 16;
	}else{
		dy = 0;
	}

	x = Scr_x + dx;
	y = Scr_y + dy;

	mx = mp->width*16-224;
	my = mp->height*16-144;

	if( x < 0 )
		x = 0;
	else if( x > mx )
		x = mx;

	if( y < 0 )
		y = 0;
	else if( y > my )
		y = my;

	if( x/16 != Scr_x/16 ){
		if( dx < 0 )
			draw_map(x-1,y-15,x-1,y+159,mp);
		else
			draw_map(x+224,y-15,x+224,y+159,mp);
	}

	if( y/16 != Scr_y/16 ){
		if( dy < 0 )
			draw_map(x-15,y-1,x+239,y-1,mp);
		else
			draw_map(x-15,y+144,x+239,y+144,mp);
	}
	Scr_x = x;
	Scr_y = y;
}

void wait_v( void )
{
	sys_wait(1);
}


void refresh_screen( void )
{
	int num;
#if 0
	static unsigned tick;
	unsigned t;
	static unsigned char buf[2];

	t = sys_get_tick_count();
	buf[0] = '0' + (t - tick) % 10;
	buf[1] = 0;
	draw_letter(buf,9,9);
	tick = t;
#endif

	wait_v();

	if( Num_spr <= 128 ){
		sprite_set_data(0,Num_spr,(void far*)Spr_buf);
		sprite_set_range(0,Num_spr);
	}else{
		num = Num_spr - Spr_start;
		if( num <= 0 ){
			num = 128;
			Spr_start = 0;
		}else if( num > 128 ){
			num = 128;
		}
		sprite_set_data(0,num,(void far*)(Spr_buf+Spr_start));
		sprite_set_range(0,num);
		Spr_start += MAX_SPRITES / 16;
	}

	Spr_wrptr = Spr_buf;
	Num_spr = 0;

	screen_set_scroll(0,Scr_x&255,Scr_y&255);
}


void draw_hero( hero_t *hp )
{
	sprite_t *sp;
	unsigned palette;

	sp = (sprite_t*)&Hero_spr[hp->stat*2+hp->dir];

	if( hp->life ){
		if( (hp->damage & 7) > 1 )
			palette = (PLT_DAMAGE & ~8) << 9;
		else
			palette = (PLT_CHAR & ~8) << 9;

		regist_sprite(sp,hp->x/4,hp->y/4,palette);
	}else{
		if( hp->damage & 8 ){
			palette = (PLT_DAMAGE & ~8) << 9;
			regist_sprite(sp,hp->x/4,hp->y/4,palette);
		}
	}
}

void draw_ene( ene_t *ep )
{
	sprite_t *sp;
	unsigned palette;

	sp = &Ene_spr[ep->graphic][ep->stat + ep->dir * 2];

	if( ep->life ){
		if( (ep->damage & 7) > 1 )
			palette = (PLT_DAMAGE & ~8) << 9;
		else 
			palette = (PLT_CHAR & ~8) << 9;

		regist_sprite(sp,ep->x/4,ep->y/4,palette);
	}else{
		if( ep->damage & 8 ){
			palette = (PLT_DAMAGE & ~8) << 9;
			regist_sprite(sp,ep->x/4,ep->y/4,palette);
		}
	}
}

void draw_letter( char far *str, int x, int y )
{
	unsigned buf[32];
	int len;

	len = 0;
	while( *str && len < 32 )
		buf[len++] = Letter_conv_table[*str++];
	screen_set_char(1,x,y,len,1,(void far*)buf);
}


void draw_life_hero( hero_t *hp )
{
	int l,x;
	static unsigned buf[8];
	unsigned *p;

	l = (long)hp->life * 64L / (long)hp->life_max;

	p = buf;
	x = 8;
	while( x <= l ){
		*p++ = PLT_LIFE<<9 | FONT_LIFE_FULL;
		x += 8;
	}

	l &= 7;
	if( l ){
		*p++ = PLT_LIFE<<9 | FONT_LIFE_HERO;
		create_lifebar(FONT_LIFE_HERO,l);
	}else{
		x -= 8;
	}

	while( x < 64 ){
		*p++ = PLT_LIFE<<9 | FONT_LIFE_EMPTY;
		x += 8;
	}
	screen_set_char(1,9,1,8,1,(void far*)buf);
}

void draw_attack( hero_t *hp )
{
	int l,x;
	static unsigned buf[8];
	unsigned *p;

	l = hp->attack_count >> 2;

	p = buf;
	x = 8;
	while( x <= l ){
		*p++ = PLT_ATTACK<<9 | FONT_ATTACK_FULL;
		x += 8;
	}

	l &= 7;
	if( l ){
		*p++ = PLT_ATTACK<<9 | FONT_ATTACK;
		create_attackbar(FONT_ATTACK,l);
	}else{
		x -= 8;
	}

	while( x < 64 ){
		*p++ = PLT_ATTACK<<9 | FONT_ATTACK_EMPTY;
		x += 8;
	}
	screen_set_char(1,9,2,8,1,(void far*)buf);

}


void draw_life_ene( ene_t *ep )
{
	int l,x;
	static unsigned buf[8];
	unsigned *p;

	l = (long)ep->life * 64L / (long)ep->life_max;

	p = buf;
	x = 8;
	while( x <= l ){
		*p++ = PLT_LIFE<<9 | FONT_LIFE_FULL;
		x += 8;
	}

	l &= 7;
	if( l ){
		*p++ = PLT_LIFE<<9 | FONT_LIFE_ENEMY;
		create_lifebar(FONT_LIFE_ENEMY,l);
	}else{
		x -= 8;
	}

	while( x < 64 ){
		*p++ = PLT_LIFE<<9 | FONT_LIFE_EMPTY;
		x += 8;
	}
	screen_set_char(1,9,3,8,1,(void far*)buf);
	if( !Ene_life_active ){
		Ene_life_active = 1;
		draw_letter("ENEMY",4,3);
	}
}

void erase_life_ene( void )
{
	if( Ene_life_active ){
		screen_fill_char(1,4,3,13,1,PLT_LETTER<<9|LETTER_FONT);
		Ene_life_active = 0;
	}
}

void show_level( int level )
{
	static char buf[8];

	if( level > 99 )
		level = 99;
	sprintf(buf,"LEVEL %2d",level);
	draw_letter(buf,20,1);
}

void show_score( unsigned score )
{
	static char buf[16];

	if( score > 30000 )
		score = 30000;
	sprintf(buf,"SC %5u00",score);
	draw_letter(buf,18,2);
}


unsigned clear_level( hero_t *hp, unsigned score, int life_bonus, int level_bonus )
{
	static char buf[32];
	int bonus;
	int i;

	sprintf(buf,"CLEAR BONUS %5d00",level_bonus);
	draw_letter(buf,5,9);
	for( i = 0 ; i < 150 ; i++ )
		wait_v();

	while( level_bonus-- ){
		sprintf(buf,"CLEAR BONUS %5d00",level_bonus);
		draw_letter(buf,5,9);
		score++;
		if( score > 60000 )
			score = 60000;
		show_score(score);
		wait_v();
	}

	for( i = 0 ; i < 150 ; i++ )
		wait_v();

	bonus = 0;
	sprintf(buf,"LIFE BONUS %5d00",0);
	draw_letter(buf,6,11);
	while( hp->life-- ){
		bonus += life_bonus;
		sprintf(buf,"LIFE BONUS %5d00",bonus);
		draw_life_hero(hp);
		draw_letter(buf,6,11);
		wait_v();
	}

	for( i = 0 ; i < 75 ; i++ )
		wait_v();

	while( bonus ){
		bonus -= life_bonus;
		sprintf(buf,"LIFE BONUS %5d00",bonus);
		draw_letter(buf,6,11);
		score += life_bonus;
		if( score > 60000 )
			score = 60000;
		show_score(score);
		wait_v();
	}
	for( i = 0 ; i < 150 ; i++ )
		wait_v();


	return score;
}

void fade_in( void )
{
	int x,y,yy;

	for( x = 0 ; x <32 ; x += 8 ){
		screen_fill_char(1,x,18,8,1,PLT_LETTER<<9|LETTER_FONT);
		wait_v();
	}

	for( y = 0 ; y < 18 ; y += 2 ){
		for( x = 0 ; x < 32 ; x += 8 ){
			screen_fill_char(1,x,y,8,1,PLT_LETTER<<9|LETTER_FONT);
			wait_v();
		}
		yy = 17 - y;
		for( x = 24 ; x >= 0 ; x -= 8 ){
			screen_fill_char(1,x,yy,8,1,PLT_LETTER<<9|LETTER_FONT);
			wait_v();
		}
	}
}


void fade_out( void )
{
	int x,y,yy;

	for( x = 0 ; x <32 ; x += 8 ){
		screen_fill_char(1,x,18,8,1,PLT_DARK<<9|LETTER_FONT);
		wait_v();
	}

	for( y = 0 ; y < 18 ; y += 2 ){
		for( x = 0 ; x < 32 ; x += 8 ){
			screen_fill_char(1,x,y,8,1,PLT_DARK<<9|LETTER_FONT);
			wait_v();
		}
		yy = 17 - y;
		for( x = 24 ; x >= 0 ; x -= 8 ){
			screen_fill_char(1,x,yy,8,1,PLT_DARK<<9|LETTER_FONT);
			wait_v();
		}
	}
	Ene_life_active = 0;
}


void draw_label( void )
{
	draw_letter("LIFE",5,1);
	draw_letter("POW",6,2);
	Ene_life_active = 0;
}

void draw_title( void )
{
	unsigned buf[32];
	int x,y;
	int i;

	font_set_colordata(0,TITLE_WIDTH*TITLE_HEIGHT,(void far*)Font_title);

	screen_fill_char(0,0,0,32,32,PLT_DARK<<9|LETTER_FONT);
	screen_set_scroll(0,0,0);

	i = 0;
	for( y = 0 ; y < TITLE_HEIGHT ; y++ ){
		for( x = 0 ; x < TITLE_WIDTH ; x++ )
			buf[x] = PLT_TITLE<<9|i++;
		screen_set_char(0,(28-TITLE_WIDTH)/2,y+2,
					TITLE_WIDTH,1,(void far*)buf);
	}
}

void draw_gameover( void )
{
	draw_letter("GAME OVER",8,10);
}


void draw_pause( int pause )
{
	if( pause ){
		draw_letter("P A U S E",8,10);
		draw_letter("PUSH Y3 TO EXIT GAME",6,12);
	}else{
		screen_fill_char(1,6,10,20,3,PLT_LETTER<<9|LETTER_FONT);
	}
}
