#include "iface.h"
#include <assert.h>

namespace voxel
{
	ZGame::ZGame()
	{
		for (int a=0; a<FIELD_N; a++)
			for (int b=0; b<FIELD_N; b++)
				h[a][b] = (rand()&255);

		for (int a=0; a<256; a++)
			for (int b=0; b<3; b++)
				pal[a][b] = (rand()&255);

		for (int a=0; a<FIELD_N; a++)
			for (int b=0; b<FIELD_N; b++)
				for (int c=0; c<FIELD_H; c++)
					clr[a][b][c] = (rand()&255);

		cam = T( -10, -10, 100 );
		dir = T( 1, 1, 0 );
		dir.normalize();

		pp[0] = ZPlayer( FIELD_N/4, FIELD_N/4, 255, 0, 0 );
		pp[1] = ZPlayer( FIELD_N*3/4, FIELD_N*3/4, 0, 0, 255 );

		for (int a=0; a<WIND_N; a++)
			wind[a] = T( (float)(rand()%FIELD_N), (float)(rand()%FIELD_N), (float)(rand()%FIELD_H) );

		wx = (rand()%21-10)*0.1f;
		wy = (rand()%21-10)*0.1f;

		locked = false;
	}

	void ZGame::gen( ZGen * g, int type )
	{
		g->gen( (uchar *)h, (uchar *)clr, (uchar *)top, (uchar *)pal, type );

		for (int a=0; a<FIELD_N; a++)
			for (int b=0; b<FIELD_N; b++)
				for (int c=0; c<FIELD_H; c++)
					if (c >= h[a][b])
						clr[a][b][c] = 0;
					else if (clr[a][b][c]==0)
						clr[a][b][c] = 1;
		pal[0][0] = pal[0][1] = pal[0][2] = 0;
	}

	void ZGame::do_move( int i )
	{
		locked = true;

		frame = 0;

		cur_pl = i;

		int cost[] = { 0, 50, 80, 120, 250, 500 };
		if (pp[i].money < cost[pp[i].weapon])
		{
			pp[i].weapon = 0;
			return;
		}

		if (pp[i].hp == 0)
		{
			pp[i].weapon = 0;
			return;
		}

		pp[i].money -= cost[pp[i].weapon];

		static float pi = acos(-1.f);
		
		if (pp[i].weapon == 1 || pp[i].weapon == 2 || pp[i].weapon == 3 || pp[i].weapon == 4)
		{
			ZBullet b;
			b.pos = T( pp[i].pos_x+0.5f, pp[i].pos_y+0.5f, h[pp[i].pos_x][pp[i].pos_y]+1.f );
			b.type = 1;
			if (pp[i].weapon == 2) b.type = 2;
			else if (pp[i].weapon == 3) b.type = 4;
			else if (pp[i].weapon == 4) b.type = 3;
			float aa = pp[i].alpha*pi/180.f, bb = pp[i].beta*pi/180.f;
			b.v = T( sin( aa )*cos( bb ), cos( aa )*cos( bb ), sin( bb ) );
			if (pp[i].weapon != 4)
			{
				b.v.x *= pp[i].power;
				b.v.y *= pp[i].power;
				b.v.z *= pp[i].power;
			}
			else
			{
				b.v.x *= 25.f;
				b.v.y *= 25.f;
				b.v.z *= 25.f;
			}
			b.dead = false;
			bullets.push_back( b );
		}
		else if (pp[i].weapon == 5)
		{
			for (int a=-1; a<=1; a++)
				for (int b=-1; b<=1; b++)
				{
					ZBullet bu;
					bu.pos = T( pp[i].X+a*5.f, pp[i].Y+b*5.f, FIELD_H*2.f );
					bu.type = 1;
					bu.v = T( 0.f, 0.f, 0.f );
					bu.dead = false;
					bullets.push_back( bu );
				}
		}
	}

	void ZGame::erase_ball( int x, int y, int z, int r )
	{
		for (int a = std::max(x-r,0); a <= std::min(x+r,FIELD_N-1); a++)
			for (int b = std::max(y-r,0); b <= std::min(y+r,FIELD_N-1); b++)
				for (int c = std::max(z-r,0); c <= std::min(z+r,FIELD_H-1); c++)
					if ( (a-x)*(a-x) + (b-y)*(b-y) + (c-z)*(c-z) <= r*r )
						clr[a][b][c] = 0;
	}

	void ZGame::do_damage( T c, float r, int damage )
	{
		for (int a=0; a<2; a++)
		{
			T p = T( pp[a].pos_x+0.5f, pp[a].pos_y+0.5f, h[pp[a].pos_x][pp[a].pos_y] + 1.f );
			float delta = (p.x-c.x)*(p.x-c.x) + (p.y-c.y)*(p.y-c.y) + (p.z-c.z)*(p.z-c.z);
			if (delta < r*r)
			{
				pp[a].hp -= damage;
				if (pp[a].hp < 0) pp[a].hp = 0;
			}
		}
	}

	void ZGame::do_anim()
	{
		if (!locked) return;

		static float pi = acos(-1.f);

		frame++;
		if (frame <= 40 && frame % 5 == 0 && pp[cur_pl].weapon == 3)
		{
			int i = cur_pl;
			ZBullet b;
			b.pos = T( pp[i].pos_x+0.5f, pp[i].pos_y+0.5f, h[pp[i].pos_x][pp[i].pos_y]+1.f );
			b.type = 4;
			float aa = (pp[i].alpha-5+rand()%11)*pi/180.f, bb = (pp[i].beta-5+rand()%11)*pi/180.f;
			b.v = T( sin( aa )*cos( bb ), cos( aa )*cos( bb ), sin( bb ) );
			b.v.x *= pp[i].power-2+rand()%5;
			b.v.y *= pp[i].power-2+rand()%5;
			b.v.z *= pp[i].power-2+rand()%5;
			b.dead = false;
			bullets.push_back( b );
		}

		bool all_dead = true;
		for (int i = 0; i < (int)bullets.size(); i++)
			if (!bullets[i].dead)
			{
				all_dead = false;
				ZBullet & b = bullets[i];
				if (b.type == 1 || b.type == 2 || b.type == 4)
				{
					//if (frame % 5 == 0)
						balls.push_back( ZBall( b.pos, 1.f, 1200, 50 ) );
					const float WIND_C = 5.f;
					const float G_C = 40.f;
					const float D_T = 0.1f;
					T F = T( wx*WIND_C, wy*WIND_C, - G_C );
					b.v.x += F.x*D_T;
					b.v.y += F.y*D_T;
					b.v.z += F.z*D_T;

					b.pos.x += b.v.x*D_T;
					b.pos.y += b.v.y*D_T;
					b.pos.z += b.v.z*D_T;
				}
				else if (b.type == 3)
				{
					//if (frame % 5 == 0)
					balls.push_back( ZBall( b.pos, 3.f, 10000, 30 ) );
					balls[(int)balls.size()-1].cur_time = 600;
					const float D_T = 0.1f;
					b.pos.x += b.v.x*D_T;
					b.pos.y += b.v.y*D_T;
					b.pos.z += b.v.z*D_T;
					erase_ball( (int)b.pos.x, (int)b.pos.y, (int)b.pos.z, 3 );
					if (frame > 10) do_damage( b.pos, 4.f, 10 );
				}

				bool boom = false;
				if (b.pos.x < 0 || b.pos.y < 0 || b.pos.z < 0)
					boom = true;
				int bx = (int)b.pos.x, by = (int)b.pos.y, bz = (int)b.pos.z;
				if (bx >= FIELD_N || by >= FIELD_N)
					boom = true;
				if (!boom && 0 <= bz && bz < h[bx][by] && clr[bx][by][bz]!=0 && b.type != 3)
					boom = true;

				if (boom)
				{
					b.dead = true;
					if (b.type == 1 || b.type == 2)
					{
						balls.push_back( ZBall( b.pos, 10.f, 10000, 100 ) );
						erase_ball( (int)b.pos.x, (int)b.pos.y, (int)b.pos.z, 10 );
						do_damage( b.pos, 10.f, 20 );
						if (b.type == 2)
							for (int q=0; q<6; q++)
							{
								ZBullet bu;
								bu.pos = b.pos;
								bu.dead = false;
								bu.type = 4;
								bu.v = T( (rand()%21-10)*1.f, (rand()%21-10)*1.f, (rand()%10+30)*1.f );
								bullets.push_back( bu );
							}
					}
					else if (b.type == 4)
					{
						balls.push_back( ZBall( b.pos, 5.f, 10000, 100 ) );
						erase_ball( (int)b.pos.x, (int)b.pos.y, (int)b.pos.z, 5 );
						do_damage( b.pos, 10.f, 5 );
					}
				}
			}

		bool all_fired = true;
		for (int a=0; a<(int)balls.size(); a++)
		{
			balls[a].cur_time += balls[a].speed;
			if (balls[a].cur_time < 1200) all_fired = false;
		}

		if (all_dead && all_fired)
		{
			for (int a=0; a<FIELD_N; a++)
				for (int b=0; b<FIELD_N; b++)
				{
					int i = 0;
					bool new_top = (h[a][b] > 0 && clr[a][b][h[a][b]-1] == 0);
					for (int q=0; q<FIELD_H; q++)
						if (clr[a][b][q])
						{
							clr[a][b][i] = clr[a][b][q];
							i++;
						}
					h[a][b] = i;
					if (new_top && h[a][b]>0) top[a][b] = clr[a][b][h[a][b]-1];
					while (i < FIELD_H)
					{
						clr[a][b][i] = 0;
						i++;
					}
				}
			bullets.clear();
			balls.clear();

			if (cur_pl == 0)
			{
				pp[0].weapon = 0;
				cur_pl = 1;
				T enemy = T( pp[0].pos_x+0.5f, pp[0].pos_y+0.5f, h[pp[0].pos_x][pp[0].pos_y] + 1.f );
				T you = T( pp[1].pos_x+0.5f, pp[1].pos_y+0.5f, h[pp[1].pos_x][pp[1].pos_y] + 1.f );
				pp[1].do_ai( you, enemy, T( wx, wy, 0.f ) );
				do_move(1);
			}
			else
			{
				pp[1].weapon = 0;

				pp[0].money += 100;
				pp[1].money += 100;
				wx = (rand()%21-10)*0.1f;
				wy = (rand()%21-10)*0.1f;
				locked = false;
			}
		}
	}
};