#define  UTIL_CRYSTALS_H aaa
//----------------------------------------------------------------------------
//  @brief
//        обработка кристаллов
//        

//  @ingroup
    
//  2006Oct19 created. Zmanovsky Peter.
//  (C) 2006    Sigma-Team
//-----------------------------------------------------------------------------

#define MAX_FC_NUM			1000
//
int LastTactLen = 0;
//
int FallingCrystals[MAX_FC_NUM];
int FCFallType     [MAX_FC_NUM];	//тип падения 1 - кристалл падает вниз, 2 - только что клетку сбили
int FCSpeedX       [MAX_FC_NUM];		
int FCSpeedY       [MAX_FC_NUM];		//скорость по y умножена на 1000
int FCOldZ         [MAX_FC_NUM];		//
//эти переменные нужны из-за проблем с целочисленным делением (чтобы кристалл не оставался на месте при больших fps)
int FC_DeltaX      [MAX_FC_NUM];		//дельта координаты x * 1000
int FC_DeltaY      [MAX_FC_NUM];		//дельта координаты y * 1000
//
//
int giFCCnt = 0;
//
int giCheatCrystX = 0;
int giCheatCrystY = 0;

//------------------------------------------------------------------------------------------
BigCrystalSetBorn(bool bCreate);

//------------------------------------------------------------------------------------------
BeiginCrystalFall(int crystal, int type)
{
	if(!crystal || /*!PlayerVehi || */giFCCnt>=MAX_FC_NUM)
		return;
	//
	int x, y, z, goaly, buf;
	x = GetX(crystal);
	y = GetY(crystal);
	z = GetZ(crystal);
	if(!PlayerVehi)
		goaly = -ToScreenY(0)+ScreenY();	//низ экрана
	else
		goaly = GetY(PlayerVehi)-GetZ(PlayerVehi);
	//
	FCFallType[giFCCnt] = type;
	if(type == 1)
	{
		buf = CreateSprite(1221, GetX(crystal), GetY(crystal), GetZ(crystal), GetDirection(crystal));
		Action(crystal, ANI_DEATH);
		Action(crystal, ACT_CHANGE_COOR, 0, 0, 0);
		crystal = buf;
		//
		Action(crystal, ACT_CHANGE_COOR, x, goaly, goaly-(y-z));
		Action(crystal, ACT_SET_SPEED, 1);
		//
		FCSpeedX       [giFCCnt] = FALLIN_CRYSTAL_SPEED_X;
		FCSpeedY       [giFCCnt] = FALLIN_CRYSTAL_SPEED_Y*1000;
		if(ToScreenX(GetX(crystal)) > (SCREEN_FIELD_RIGHT+SCREEN_FIELD_LEFT)/2)
			FCSpeedX[giFCCnt] = -FCSpeedX[giFCCnt];
	}
	else
	if(type == 2)
	{
		FCOldZ[giFCCnt] = 0;//GetZ(crystal);
		FCSpeedY[giFCCnt] = NEW_CRYSTAL_SPEED_Z*1000;
		Action(crystal, ACT_CHANGE_COOR, GetX(crystal), GetY(crystal), NEW_CRYSTAL_INIT_Z);
	}
	else
	if(type == 3)
	{
		FCSpeedX[giFCCnt] = WIN_GOLD_SPEED_X_MIN + Random(WIN_GOLD_SPEED_X_MAX-WIN_GOLD_SPEED_X_MIN);
		if(Random(1))
			FCSpeedX[giFCCnt] = -FCSpeedX[giFCCnt];
		//
		FCSpeedY[giFCCnt] = WIN_GOLD_SPEED_Y_MIN + Random(WIN_GOLD_SPEED_Y_MAX-WIN_GOLD_SPEED_Y_MIN);
		if(Random(1))
			FCSpeedY[giFCCnt] = -FCSpeedY[giFCCnt];
		FCSpeedY[giFCCnt] = FCSpeedY[giFCCnt] * 1000;
	}
	else
	if(type == 4)
	{
		FCSpeedX[giFCCnt] = 10 + Random(90-10);
		if(x > ScreenX()/2)
			FCSpeedX[giFCCnt] = -FCSpeedX[giFCCnt];
		//
		FCSpeedY[giFCCnt] = -30 - Random(150-30);
		FCSpeedY[giFCCnt] = FCSpeedY[giFCCnt] * 1000;
	}
	//
	FallingCrystals[giFCCnt] = crystal;
	FC_DeltaX      [giFCCnt] = 0;
	FC_DeltaY      [giFCCnt] = 0;
	giFCCnt++;
}


//------------------------------------------------------------------------------------------
RemoveCrystal(int crystal)
{
	int i;
	for(i = 0; i < giFCCnt; i++)
	{
		if(FallingCrystals[i] == crystal)
		{
			FallingCrystals[i] = FallingCrystals[giFCCnt-1];
			FCSpeedX       [i] = FCSpeedX		[giFCCnt-1];
			FCSpeedY       [i] = FCSpeedY		[giFCCnt-1];
			FC_DeltaX      [i] = FC_DeltaX      [giFCCnt-1];
			FC_DeltaY      [i] = FC_DeltaY      [giFCCnt-1];
			FCFallType     [i] = FCFallType     [giFCCnt-1];
			FCOldZ         [i] = FCOldZ         [giFCCnt-1];
			//
			giFCCnt--;
			break;
		}
	}
}


//------------------------------------------------------------------------------------------
CrystalsFallTact()
{
	int i;
	for(i = 0; i < giFCCnt; )
	{
		int unit; unit = FallingCrystals[i];
		//
		FC_DeltaY[i] = FC_DeltaY[i] + LastTactLen*FCSpeedY[i]/1000;
		int dy; dy = FC_DeltaY[i] / 1000;
		FC_DeltaY[i] = FC_DeltaY[i] - dy*1000;
		//
		if(FCFallType[i] == 1 || FCFallType[i] == 3 || FCFallType[i] == 4)
		{
			FC_DeltaX[i] = FC_DeltaX[i] + LastTactLen*FCSpeedX[i];
			int dx; dx = FC_DeltaX[i] / 1000;
			FC_DeltaX[i] = FC_DeltaX[i] - dx*1000;
			//
			int acc = FALLIN_CRYSTAL_SPEED_Y_ACC;
			if(FCFallType[i] == 3)
				acc = WIN_GOLD_SPEED_Y_ACC;
			FCSpeedY[i] = FCSpeedY[i] + LastTactLen * acc;
			//
			Action(unit, ACT_CHANGE_COOR, GetX(unit)+dx, GetY(unit)+dy, GetZ(unit));
		}
		else
		if(FCFallType[i] == 2)
		{
			int newz;
			newz = GetZ(unit)+dy;
			if(newz < FCOldZ[i])
			{
				newz = FCOldZ[i];
				RemoveCrystal(unit);
			}
			Action(unit, ACT_CHANGE_COOR, GetX(unit), GetY(unit), newz);
			FCSpeedY[i] = FCSpeedY[i] + LastTactLen * NEW_CRYSTAL_SPEED_Z_ACC;
		}
		//
		i++;
	}
}


//------------------------------------------------------------------------------------------
CrystallBallHit(int crystal)
{
	if(crystal && GetAnimation(crystal) != ANI_DEATH && GetAnimation(crystal) != ANI_DEATH2
		&& !Action(crystal, ACT_GET_TIMER))
	{
		//Action(crystal, ANI_DEATH);		//если просто подбирать
		RemoveCrystal(crystal);
		BeiginCrystalFall(crystal, 1);
	}
}


//------------------------------------------------------------------------------------------
AddCrystalScore()
{
	giCrystalScore++;
	//добавляем жизнь за CRYSTALS_FOR_LIFE кристаллов
	if(giCrystalScore % CRYSTALS_FOR_LIFE == 0)
	{
		bool t = AddLife(AL_CRYSTALS);
		Animate20Crystals(t);
	}
	giCrystLevScore++;
	giCrystSubLevScore++;
	//
	gScoreTot += SCORES_FOR_CRYSTALL*10;
}


//------------------------------------------------------------------------------------------
CrystalsTact()
{
	static int PrevTime = 0;
	if(PrevTime != 0)
		LastTactLen = GetTime() - PrevTime;
	if(LastTactLen < 0)	//из-за паузы такое бывает
		LastTactLen = 0;
	PrevTime = GetTime();
	//
	int ball, crystal;

	//сбивание кристаллов шариками
	for(ball = FirstUnit(U_UNIT); ball; ball = NextUnit())
	{
		if( GetVidData(GetUnitVid(ball), VID_CLASS) == B_BALL)
		{
			int radius;
			radius = GetVidData(GetUnitVid(ball), VID_SIZE_X)/2;	//радиус шарика
			radius = radius + GetVidData(1222, VID_SIZE_X)/2;	//радиус клетки с кристаллом
			radius = radius-1;
			//
			crystal = FindNearestSprite(GETSPRITE_VID+1220, GetX(ball), GetY(ball)-GetZ(ball), radius);
			CrystallBallHit(crystal);
		}
	}
	//
	if(giCheatCrystX != 0)
	{
		crystal = FindNearestSprite(GETSPRITE_VID+1220, giCheatCrystX, giCheatCrystY, 50);
		CrystallBallHit(crystal);
	}
	//
	CrystalsFallTact();

	//подбор кристаллов ракеткой
	int i;
	for(i = 0; i < giFCCnt; i++)
	{
		crystal = FallingCrystals[i];
		if( IntersectWithVehi(crystal, true, false) && FCFallType[i] != 3 )
		{
			Action(crystal, ANI_DEATH2);
			//
			if(FCFallType[i] == 4)
				PlaySFX(51);
			//
			if(FCFallType[i] != 4)
			{
				AddCrystalScore();
			}
			else
			{
				//для монеток
				gScoreTot += 10*10;
			}
			//
			RemoveCrystal(crystal);
		}
		else
		{
			//если уже сильно улетел, то убиваем его
			if(ToScreenY(GetY(crystal), GetZ(crystal)) > ScreenY() + 100)
			{
				Action(crystal, ANI_DEATH);
				RemoveCrystal(crystal);
			}
		}
	}
	//
	giCheatCrystX = 0;
	giCheatCrystY = 0;
	//
	static int PrevSubLev = -1;
	if(PrevSubLev != giSubLevelNum && giCrystSubLevScore == giCrystOnLev && giCrystSubLevScore > 0)
	{
		if(GameState != GAMESTATE_WIN)
			BigCrystalSetBorn(true);
		PrevSubLev = giSubLevelNum;
	}
}


//------------------------------------------------------------------------------------------
F1220_14(int unit)
{
	if(unit)	//пауза чтобы мгновенно не собраться
	{
		Action(unit, ACT_SET_TIMER, 100);
		BeiginCrystalFall(unit, 2);
	}
}


//------------------------------------------------------------------------------------------
DeathOfFlower(int unit, bool bPlaySfx)
{
	int xx, yy, zz, dir;
	xx = GetX(unit); yy = GetY(unit); zz = GetZ(unit); dir = GetDirection(unit);
	Action(unit, ACT_CHANGE_COOR, 0, 0, 0);
	Action(unit, ANI_DEATH2);
	if(bPlaySfx)
		PlaySFX(51);
	//
	if(GetUnitVid(unit) == 1222)
		CreateSprite(1225, xx, yy, zz, dir);
	else
	if(GetUnitVid(unit) == 1230)
		CreateSprite(1231, xx, yy, zz, dir);
}


//------------------------------------------------------------------------------------------
DeathOfCrystals()
{
	int bigCryst = 0;
	//
	int unit;
	for(unit=FirstInBox(0, -ToScreenY(0), 1024, 768-ToScreenY(0)); unit; unit=NextInBox())
	{
		if( !IsDying(unit) && (GetUnitVid(unit) == 1237 || GetUnitVid(unit) == 1235
							 || GetUnitVid(unit) == 1242))
		{
			bigCryst = unit;
		}
		else
		if( GetUnitVid(unit) == 1220 && !IsDying(unit) )
		{
			RemoveCrystal(unit);
			Action(unit, ANI_DEATH2);
		}
		else
		if(GetUnitVid(unit) == 1222 || GetUnitVid(unit) == 1230)
			DeathOfFlower(unit, false);
	}
	//
	if(bigCryst)
	{
		CreateSprite(1226, GetX(bigCryst), GetY(bigCryst), GetZ(bigCryst)+5, GetDirection(bigCryst));
		Destroy(bigCryst);
	}
	//
	BigCrystalSetBorn(false);
}


//------------------------------------------------------------------------------------------
CreateFallingGold()
{
	static int PrevTime = 0;
	//
	//рожаем 1 раз в WIN_GOLD_PERIOD_TIME милисекунд
	if(PrevTime && GetTime()-PrevTime >= 0 && GetTime()-PrevTime < WIN_GOLD_PERIOD_TIME)
		return;
	//
	PrevTime = GetTime();
	//
	int gX = 0;
	int gY = 0;
	int gold = FindNearestSprite(GETSPRITE_VID+1306, 0, 0, 3000);
	if(gold)
	{
		gX = GetX(gold);
		gY = GetY(gold) - GetZ(gold) - 35;
	}
	//
	int i, j;
	for(j = 0; j < WIN_GOL_VIDS_COUNT; j++)
	{
		int NoDir = GetVidData(bWinGoldVids[j], VID_NO_DIR);
		for(i = 0; i < bWinGoldVidsCnt[j]; i++)
		{
			int dir = Random(NoDir);
			dir = Call_ii(EXT_GetAbsDir, bWinGoldVids[j], dir);
			BeiginCrystalFall(CreateSprite(bWinGoldVids[j], gX-70+Random(140), gY-45+Random(90), 0, dir), 3);
		}
	}
}


//------------------------------------------------------------------------------------------
HideWinObjects()
{
	int  j;
	for(j = 0; j < WIN_GOL_VIDS_COUNT; j++)
		Genocide(bWinGoldVids[j]);
	Genocide(1307);
}


//------------------------------------------------------------------------------------------
BigCrystalSetBorn(bool bCreate)
{
	int spr = GetVidOnScreen(1238);
	if(!spr)
		spr = GetVidOnScreen(1241);
	if(spr)
	{
		if(bCreate)
			Action(spr, ACT_SET_DEATH_TIMER, 700);
		else
			Action(spr, ACT_SET_DEATH_TIMER, 999999);
	}
}


//------------------------------------------------------------------------------------------
CreateGoldBonus(int x, int y)
{
	int num = 0;
	/*int b = 10;
	while(1)
	{
		num = Random(WIN_GOL_VIDS_COUNT-1);
		if(b<0 || bWinGoldVids[num] != 1316)
			break;
		b--;
	}
	//
	int NoDir = GetVidData(bWinGoldVids[num], VID_NO_DIR);
	int dir = 0;
	if(NoDir > 1)
		dir = Random(NoDir-1);*/
	int dir = 1;
	dir = Call_ii(EXT_GetAbsDir, bWinGoldVids[num], dir);
	//
	BeiginCrystalFall(CreateSprite(bWinGoldVids[num], x, y, 0, dir), 4);
}


//------------------------------------------------------------------------------------------
//на damage большого кристалла - наносим только шариком
F1237_DAMAGE(int unit,int beating_unit,int damage)
{
	if(!beating_unit)	//это значит, что от шарика damage пришел
		return 0;
	//
	return 1;
}

